Select Git revision
ControlPoint.cpp
-
kledmundson authored
* Updated the cmake version to 3.10 * Adding configurations for gtest * Tweaking things for gtest * Got gtest working and made a small example test * Updated the cmake version to be 3.10 or greater * Added test file discovery support and seperated the main into another file * Added more tests for FileName * Updated with the new testing guidelines and added new tests. * Added gmock * PixelTest (#536) * initial Pixel test * Add more test cases for Pixel * testing parameterization in Pixel test * testing function parameterization * parameterize static vs object methods * basic PixelTests implementation * clean up and more static tests * update PixelTests with float/dbl expects * Refactored stats to a functions * Modified to have cubeit remove mosaic pixel tracking info from labels. Fixes #5533 * Update cubeit.xml Fixed a typo * Fixes conda channels in Jenkinsfile & adds a MacOS node (#633) * Merged dev and cleaned up header conflicts * Update for #619. * Fix libtiff dependency (#636) (#644) * Upgrade libtiff to 4.0.10 (#636) * Switch libtiff to 4.0.9 or higher to remove geotiff conflict * Moved ISIS3 conda-build recipe from ISIS3_deps repository (#650) * Fixed warning in Pixel unit tests * Removing build numbers from external libraries (#660) * Moved ISIS3 conda-build recipe from ISIS3_deps repository * Un-pinned non-astro build numbers * Removing build numbers from external libraries in the environment and meta.yeml files * Final merging * Added pixel type attribute to the output image of program shadow. Fixes #5187 (#659) * Removed bolding of some text to decrease distraction. * Fixed some typos. * Reworded documentation. * Added section for Environment and PreferemcesSetup in the Getting Started Section. (#663) * Updated .gitmodules to use https rather than ssh (#673) * Added build type release to conda recipe (#676) * Updates README with Discourse (#690) * Updates README with Discourse * Update README.md * Update README.md * Added fix to Spice Server to accept clients with version nums >=3.5.*.* (#780) * Fixed error when trying to export a compressed image using pds2hideal. Fixes #5525. (#2059) * Added capability to export a compressed image with tables missing RECORD_BYTES keyword. Added test for compressed image. * Changed names of test output cubes. * Adding explanatory comments to the meta.yaml file (#2358) * Adding explanatory comments to the recipes/meta.yaml * Replacing accidentally erased line * Multisegment DSK support for Bullet engine (#2791) * Merged multisegment DSKs for Bullet * basic tests * removed original tests * Minor updates to download sizes and some text. (#2790) * Phocube will export RA and declination planes even if the point is not on the planet. Fixes #4446 (#657) * Made it so that RA and Dec are added last. * Updated code to be up to standards. * Added RA and dec test. * Updated history comment. * Renamed test. * Fixed typo in documentation * Refactored code so that RA and dec are placed in the correct bands instead of moving them to the last two bands. * Updated documentation, test now checks cube label. * Fixed SummingMode keyword being set in tgocassis2isis (#2847) * Adding Expanded keyword to cassis label and modifying SummingMode keyword * Updating the window count value * Adding capacity to handle imports without Expanded tag * Setting tgocassismos to have tracking turned-on (#2856) * Adding parameter "tracking=true" to tgocassismos call to automos * Adding documentation * Fixing indentation in documentation * Updates to tgocassisrdrgen and ProcessExportPds4 to add content to exported CaSSIS Label. (#2858) * Add 32-bit ISIS Special Pixel Constants to ProcessExportPds4 * Add ability to set title and version id in exported PDS4 produce in tgocassisrdrgen and ProcessExportPds4 API * Fix bug that occurs when exporting mosaics with Archive groups and fixed min/max lat/lon to east/west bounding box positive east flip bug * Added docs. * Update schema to most recent versions and comment-out schema that isn't used (temporarily) in tgocassisrdrgen. * Adds Issue Templates to Issues (#664) * Adds issue templates * Verbage update * Updates issue template for questions (#3131) Removed a newline in the header that I believe was causing the automatic template detection to fail. * Added gtest for ID and split TestUtilities into a cpp and h file to fix duplicate symbol error when building. (#2824) Code reviewed and tested * tgocassisrdrgen exported label re-order. (#3135) * Add 32-bit ISIS Special Pixel Constants to ProcessExportPds4 * Add ability to set title and version id in exported PDS4 produce in tgocassisrdrgen and ProcessExportPds4 API * Fix bug that occurs when exporting mosaics with Archive groups and fixed min/max lat/lon to east/west bounding box positive east flip bug * Added docs. * Update schema to most recent versions and comment-out schema that isn't used (temporarily) in tgocassisrdrgen. * Added reorder function to ProcessExportPds4 to reorder xml files generated in the wrong order for PDS4 and added cassis-specific schema * Update label generated by tgocassisrdrgen from additional feedback (#3137) * Add 32-bit ISIS Special Pixel Constants to ProcessExportPds4 * Add ability to set title and version id in exported PDS4 produce in tgocassisrdrgen and ProcessExportPds4 API * Fix bug that occurs when exporting mosaics with Archive groups and fixed min/max lat/lon to east/west bounding box positive east flip bug * Added docs. * Update schema to most recent versions and comment-out schema that isn't used (temporarily) in tgocassisrdrgen. * Added reorder function to ProcessExportPds4 to reorder xml files generated in the wrong order for PDS4 and added cassis-specific schema * Add StopTime to tgocassismos's Mosaic PVL group, as it is required for PDS4 export. Also, fix time formatting and east_azimuth units * Remove comment * Updated truthdata for ProcessExportPds4 class to match updates made for CaSSIS sprint (#3146) * Fix time-formatting in reingested CaSSIS images. (#3149) * Updated truthdata for ProcessExportPds4 class to match updates made for CaSSIS sprint * Fix trailing Z time-format in tgocassis2isis when reingesting images exported from ISIS3 * Added LineEqationTests.cpp (#3152) * History entry added to cube after running sumspice. Fixes #4972. (#658) * Added WriteHistory() method to SumFinder. * Renamed method. * Refactored writeHistory to be up to isis standards. * Added history entries and updated code to be up to isis standards. * Updated history entry. * adding dedicated BundleLidarPointVector class * adding dedicated BundleLidarPointVector class * adding dedicated BundleLidarPointVector class * Various minor mods to the readme (#3165) * Added FileList test (#3168) * Added LineEqationTests.cpp * Added FileListTests.cpp Implemented an istream constructor in FileList.cpp to help with testing. * added FileList tests. implemented istream constructor for FileList.cpp to help with testing. * fixed whitespace issues in FileListTests.cpp * Update FileListTests.cpp * Cleaned up data area wording in install guide (#3170) * temp commits for testing bundle with lidar * temp commits to bundle lidar * Add ISIS3 update instructions to README (#3175) * Merged multisegment DSKs for Bullet * updated with update instructions * isis->isis3 * added header * Updating Contributing.md (#3179) * Merged multisegment DSKs for Bullet * updated with update instructions * isis->isis3 * added header * updated contributing guidelines * removed mentions of TC * Added LatitudeTest using Gtest (#3160) * Added gtest for ID and split TestUtilities into a cpp and h file to fix duplicate symbol error when building. * Created LatitudeTests. * Added C-Shell variable setup (#3173) * Added C-Shell variable setup * Fixed history * Made a bit more pythonic * Updates BulletDSKShape's methods for multisegment DSKs (#3181) * fixed DSK segment methods * fixed some errors * added contraints * fixed bug where an extra segment was added * Fixed memory leak in Bullet shape model (#3180) * Added AffineTests (#3166) * Add Longitude gtest (rebase of #601) (#3182) * Created gtest for Longitude class * Remove old Longitude test * Fix syntax for Longitude Tests * Remove comment * Revert "Remove old Longitude test" This reverts commit 608d3fd5c32d7e4a1de7fec407697a0147fbfae0. * Cleaned file, organzied test cases * Fixed failing copy constructor test * Fixed bug where findrx was not adding a history blob to the input cube (#3186) * Added writeHistory to findrx. * Rearranged includes in findrx. * Removed extra exceptions writing controlnets (#3185) * Fixed bug where focal plane measured x,y coordinates were not set if the cam->SetImage call failed, References #2591). (#3193) * updates to ControlPoint::ComputeApriori * Fixed bug where focal plane measured x,y coordinates were not set if the cam->SetImage call failed (References #2591). Added check to IsConstrained() method to see if point type is Free, in which case we ignore stored a priori sigmas on the coordinates. * added isis error when GenericTransform::calculateInverse gets empty matrix (#3195) * Writing 0 Value Residuals to PVL (#3194) * Allowed writting of residuals when value is zero to controlnet pvl * Updated ControlNetVersioner unit test * Fixing errors introduced with the changes to ProcessExportPds4.cpp for the tgo sprint. (#3202) * Github/Discuss Documentation Update (#3203) * Updated website documentation to point to github and discuss where appropriate * Updated last install link * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and tru… (#3200) * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and truthfile. * changed expectedOutput values for some of the tests * Update README.md (#3204) Updated to include instructions for release candidate builds on anaconda * Added gtests for Displacement.cpp, removed Displacement unitTest and truthfile. (#3209) * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and truthfile. * changed expectedOutput values for some of the tests * Made tests for Displacement.cpp using gtest. removed Displacement unitTest and truthfile. * Updated README data area instructions (#3214) * Fixed data area instructions in README and some links * Fixed bold in block quote * Fixed legacy install guide link * extra l * Testing indentation list * Testing indentation list again * Testing indentation list code snippet * Minor wording clean up * Removed extra number * Removed duplicate Mars Odyssey entry * Updates to the build recipe for ISIS releases for the 3.7.0 release candidate. (#3205) * Minor modifications for RC build * Small modification to version in the recipe/meta.yaml * Updating release stage in isis/version * Added Area3DTests.cpp (#3216) * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and truthfile. * changed expectedOutput values for some of the tests * Made tests for Displacement.cpp using gtest. removed Displacement unitTest and truthfile. * Added Area3DTests.cpp, removed Area3D truthfile and unit test. * included TestUtilities.h for use with exception testing, added a test for teh Area3D '=' operator * changed formatting to adhere to USGS coding standards * re-addedd the unit test and truth file * gllssi2isis Original Label Fix (#3226) * Allowed writting of residuals when value is zero to controlnet pvl * Updated ControlNetVersioner unit test * Fixed pvl labels original pvl labels not being written to the resulting cube. * Updated docstrings and history for updated methods * Removed the need to set the output cube pixel type * Reverted proceeimport changes * Set the dimensions in the process before processing * Added missing 1 in a history record * Reverted and applied a more appropriate fix * Used outfile obtained at the beginning of the program * Added history comment to app xml * Removed accidental comma (#3230) * Update README.md (#3232) Update readability * Modifying files for conda build for ISIS3.7.0_RC2 (#3229) * Modifying files for conda build for ISIS3.7.0_RC_2 * Changes to modifications until issue #3231 can be completed * Small typo * One final added comment for clarification * Adding tab completion for tcsh on conda activation (#3244) * updates for bundle lidar * updates for bundle lidar * added history comment noting that piecewise polynomial functionality has been disabled to get the lidar stuff working * updates for bundle with lidar * removed commented code
kledmundson authored* Updated the cmake version to 3.10 * Adding configurations for gtest * Tweaking things for gtest * Got gtest working and made a small example test * Updated the cmake version to be 3.10 or greater * Added test file discovery support and seperated the main into another file * Added more tests for FileName * Updated with the new testing guidelines and added new tests. * Added gmock * PixelTest (#536) * initial Pixel test * Add more test cases for Pixel * testing parameterization in Pixel test * testing function parameterization * parameterize static vs object methods * basic PixelTests implementation * clean up and more static tests * update PixelTests with float/dbl expects * Refactored stats to a functions * Modified to have cubeit remove mosaic pixel tracking info from labels. Fixes #5533 * Update cubeit.xml Fixed a typo * Fixes conda channels in Jenkinsfile & adds a MacOS node (#633) * Merged dev and cleaned up header conflicts * Update for #619. * Fix libtiff dependency (#636) (#644) * Upgrade libtiff to 4.0.10 (#636) * Switch libtiff to 4.0.9 or higher to remove geotiff conflict * Moved ISIS3 conda-build recipe from ISIS3_deps repository (#650) * Fixed warning in Pixel unit tests * Removing build numbers from external libraries (#660) * Moved ISIS3 conda-build recipe from ISIS3_deps repository * Un-pinned non-astro build numbers * Removing build numbers from external libraries in the environment and meta.yeml files * Final merging * Added pixel type attribute to the output image of program shadow. Fixes #5187 (#659) * Removed bolding of some text to decrease distraction. * Fixed some typos. * Reworded documentation. * Added section for Environment and PreferemcesSetup in the Getting Started Section. (#663) * Updated .gitmodules to use https rather than ssh (#673) * Added build type release to conda recipe (#676) * Updates README with Discourse (#690) * Updates README with Discourse * Update README.md * Update README.md * Added fix to Spice Server to accept clients with version nums >=3.5.*.* (#780) * Fixed error when trying to export a compressed image using pds2hideal. Fixes #5525. (#2059) * Added capability to export a compressed image with tables missing RECORD_BYTES keyword. Added test for compressed image. * Changed names of test output cubes. * Adding explanatory comments to the meta.yaml file (#2358) * Adding explanatory comments to the recipes/meta.yaml * Replacing accidentally erased line * Multisegment DSK support for Bullet engine (#2791) * Merged multisegment DSKs for Bullet * basic tests * removed original tests * Minor updates to download sizes and some text. (#2790) * Phocube will export RA and declination planes even if the point is not on the planet. Fixes #4446 (#657) * Made it so that RA and Dec are added last. * Updated code to be up to standards. * Added RA and dec test. * Updated history comment. * Renamed test. * Fixed typo in documentation * Refactored code so that RA and dec are placed in the correct bands instead of moving them to the last two bands. * Updated documentation, test now checks cube label. * Fixed SummingMode keyword being set in tgocassis2isis (#2847) * Adding Expanded keyword to cassis label and modifying SummingMode keyword * Updating the window count value * Adding capacity to handle imports without Expanded tag * Setting tgocassismos to have tracking turned-on (#2856) * Adding parameter "tracking=true" to tgocassismos call to automos * Adding documentation * Fixing indentation in documentation * Updates to tgocassisrdrgen and ProcessExportPds4 to add content to exported CaSSIS Label. (#2858) * Add 32-bit ISIS Special Pixel Constants to ProcessExportPds4 * Add ability to set title and version id in exported PDS4 produce in tgocassisrdrgen and ProcessExportPds4 API * Fix bug that occurs when exporting mosaics with Archive groups and fixed min/max lat/lon to east/west bounding box positive east flip bug * Added docs. * Update schema to most recent versions and comment-out schema that isn't used (temporarily) in tgocassisrdrgen. * Adds Issue Templates to Issues (#664) * Adds issue templates * Verbage update * Updates issue template for questions (#3131) Removed a newline in the header that I believe was causing the automatic template detection to fail. * Added gtest for ID and split TestUtilities into a cpp and h file to fix duplicate symbol error when building. (#2824) Code reviewed and tested * tgocassisrdrgen exported label re-order. (#3135) * Add 32-bit ISIS Special Pixel Constants to ProcessExportPds4 * Add ability to set title and version id in exported PDS4 produce in tgocassisrdrgen and ProcessExportPds4 API * Fix bug that occurs when exporting mosaics with Archive groups and fixed min/max lat/lon to east/west bounding box positive east flip bug * Added docs. * Update schema to most recent versions and comment-out schema that isn't used (temporarily) in tgocassisrdrgen. * Added reorder function to ProcessExportPds4 to reorder xml files generated in the wrong order for PDS4 and added cassis-specific schema * Update label generated by tgocassisrdrgen from additional feedback (#3137) * Add 32-bit ISIS Special Pixel Constants to ProcessExportPds4 * Add ability to set title and version id in exported PDS4 produce in tgocassisrdrgen and ProcessExportPds4 API * Fix bug that occurs when exporting mosaics with Archive groups and fixed min/max lat/lon to east/west bounding box positive east flip bug * Added docs. * Update schema to most recent versions and comment-out schema that isn't used (temporarily) in tgocassisrdrgen. * Added reorder function to ProcessExportPds4 to reorder xml files generated in the wrong order for PDS4 and added cassis-specific schema * Add StopTime to tgocassismos's Mosaic PVL group, as it is required for PDS4 export. Also, fix time formatting and east_azimuth units * Remove comment * Updated truthdata for ProcessExportPds4 class to match updates made for CaSSIS sprint (#3146) * Fix time-formatting in reingested CaSSIS images. (#3149) * Updated truthdata for ProcessExportPds4 class to match updates made for CaSSIS sprint * Fix trailing Z time-format in tgocassis2isis when reingesting images exported from ISIS3 * Added LineEqationTests.cpp (#3152) * History entry added to cube after running sumspice. Fixes #4972. (#658) * Added WriteHistory() method to SumFinder. * Renamed method. * Refactored writeHistory to be up to isis standards. * Added history entries and updated code to be up to isis standards. * Updated history entry. * adding dedicated BundleLidarPointVector class * adding dedicated BundleLidarPointVector class * adding dedicated BundleLidarPointVector class * Various minor mods to the readme (#3165) * Added FileList test (#3168) * Added LineEqationTests.cpp * Added FileListTests.cpp Implemented an istream constructor in FileList.cpp to help with testing. * added FileList tests. implemented istream constructor for FileList.cpp to help with testing. * fixed whitespace issues in FileListTests.cpp * Update FileListTests.cpp * Cleaned up data area wording in install guide (#3170) * temp commits for testing bundle with lidar * temp commits to bundle lidar * Add ISIS3 update instructions to README (#3175) * Merged multisegment DSKs for Bullet * updated with update instructions * isis->isis3 * added header * Updating Contributing.md (#3179) * Merged multisegment DSKs for Bullet * updated with update instructions * isis->isis3 * added header * updated contributing guidelines * removed mentions of TC * Added LatitudeTest using Gtest (#3160) * Added gtest for ID and split TestUtilities into a cpp and h file to fix duplicate symbol error when building. * Created LatitudeTests. * Added C-Shell variable setup (#3173) * Added C-Shell variable setup * Fixed history * Made a bit more pythonic * Updates BulletDSKShape's methods for multisegment DSKs (#3181) * fixed DSK segment methods * fixed some errors * added contraints * fixed bug where an extra segment was added * Fixed memory leak in Bullet shape model (#3180) * Added AffineTests (#3166) * Add Longitude gtest (rebase of #601) (#3182) * Created gtest for Longitude class * Remove old Longitude test * Fix syntax for Longitude Tests * Remove comment * Revert "Remove old Longitude test" This reverts commit 608d3fd5c32d7e4a1de7fec407697a0147fbfae0. * Cleaned file, organzied test cases * Fixed failing copy constructor test * Fixed bug where findrx was not adding a history blob to the input cube (#3186) * Added writeHistory to findrx. * Rearranged includes in findrx. * Removed extra exceptions writing controlnets (#3185) * Fixed bug where focal plane measured x,y coordinates were not set if the cam->SetImage call failed, References #2591). (#3193) * updates to ControlPoint::ComputeApriori * Fixed bug where focal plane measured x,y coordinates were not set if the cam->SetImage call failed (References #2591). Added check to IsConstrained() method to see if point type is Free, in which case we ignore stored a priori sigmas on the coordinates. * added isis error when GenericTransform::calculateInverse gets empty matrix (#3195) * Writing 0 Value Residuals to PVL (#3194) * Allowed writting of residuals when value is zero to controlnet pvl * Updated ControlNetVersioner unit test * Fixing errors introduced with the changes to ProcessExportPds4.cpp for the tgo sprint. (#3202) * Github/Discuss Documentation Update (#3203) * Updated website documentation to point to github and discuss where appropriate * Updated last install link * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and tru… (#3200) * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and truthfile. * changed expectedOutput values for some of the tests * Update README.md (#3204) Updated to include instructions for release candidate builds on anaconda * Added gtests for Displacement.cpp, removed Displacement unitTest and truthfile. (#3209) * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and truthfile. * changed expectedOutput values for some of the tests * Made tests for Displacement.cpp using gtest. removed Displacement unitTest and truthfile. * Updated README data area instructions (#3214) * Fixed data area instructions in README and some links * Fixed bold in block quote * Fixed legacy install guide link * extra l * Testing indentation list * Testing indentation list again * Testing indentation list code snippet * Minor wording clean up * Removed extra number * Removed duplicate Mars Odyssey entry * Updates to the build recipe for ISIS releases for the 3.7.0 release candidate. (#3205) * Minor modifications for RC build * Small modification to version in the recipe/meta.yaml * Updating release stage in isis/version * Added Area3DTests.cpp (#3216) * Added BasisFunctionTests.cpp. Removed BasisFunction unit test and truthfile. * changed expectedOutput values for some of the tests * Made tests for Displacement.cpp using gtest. removed Displacement unitTest and truthfile. * Added Area3DTests.cpp, removed Area3D truthfile and unit test. * included TestUtilities.h for use with exception testing, added a test for teh Area3D '=' operator * changed formatting to adhere to USGS coding standards * re-addedd the unit test and truth file * gllssi2isis Original Label Fix (#3226) * Allowed writting of residuals when value is zero to controlnet pvl * Updated ControlNetVersioner unit test * Fixed pvl labels original pvl labels not being written to the resulting cube. * Updated docstrings and history for updated methods * Removed the need to set the output cube pixel type * Reverted proceeimport changes * Set the dimensions in the process before processing * Added missing 1 in a history record * Reverted and applied a more appropriate fix * Used outfile obtained at the beginning of the program * Added history comment to app xml * Removed accidental comma (#3230) * Update README.md (#3232) Update readability * Modifying files for conda build for ISIS3.7.0_RC2 (#3229) * Modifying files for conda build for ISIS3.7.0_RC_2 * Changes to modifications until issue #3231 can be completed * Small typo * One final added comment for clarification * Adding tab completion for tcsh on conda activation (#3244) * updates for bundle lidar * updates for bundle lidar * added history comment noting that piecewise polynomial functionality has been disabled to get the lidar stuff working * updates for bundle with lidar * removed commented code
ControlPoint.cpp 62.34 KiB
#include "IsisDebug.h"
#include "ControlPoint.h"
#include <boost/numeric/ublas/symmetric.hpp>
#include <boost/numeric/ublas/io.hpp>
#include <QDebug>
#include <QHash>
#include <QString>
#include <QStringList>
#include "Application.h"
#include "CameraDetectorMap.h"
#include "CameraDistortionMap.h"
#include "CameraFocalPlaneMap.h"
#include "CameraGroundMap.h"
#include "ControlMeasure.h"
#include "ControlMeasureLogData.h"
#include "ControlNet.h"
#include "Cube.h"
#include "IString.h"
#include "Latitude.h"
#include "Longitude.h"
#include "PvlObject.h"
#include "SerialNumberList.h"
#include "SpecialPixel.h"
#include "Statistics.h"
using boost::numeric::ublas::symmetric_matrix;
using boost::numeric::ublas::upper;
using namespace std;
namespace Isis {
/**
* Construct a control point
*
* @author tsucharski (5/5/2010)
*
*/
ControlPoint::ControlPoint() : invalid(false) {
measures = NULL;
cubeSerials = NULL;
measures = new QHash< QString, ControlMeasure * >;
cubeSerials = new QStringList;
type = Free;
dateTime = "";
editLock = false;
ignore = false;
jigsawRejected = false;
referenceExplicitlySet = false;
aprioriSurfacePointSource = SurfacePointSource::None;
aprioriRadiusSource = RadiusSource::None;
parentNetwork = NULL;
referenceMeasure = NULL;
numberOfRejectedMeasures = 0;
constraintStatus.reset();
}
/**
* Copy the given control point into this instance.
*
* @param other The control point to duplicate
*/
ControlPoint::ControlPoint(const ControlPoint &other) {
measures = NULL;
cubeSerials = NULL;
referenceMeasure = NULL;
parentNetwork = NULL;
editLock = false;
measures = new QHash< QString, ControlMeasure * >;
cubeSerials = new QStringList;
QListIterator<QString> i(*other.cubeSerials);
while (i.hasNext()) {
QString sn = i.next();
const ControlMeasure *otherCm = other.GetMeasure(sn);
ControlMeasure *newMeasure = new ControlMeasure(*otherCm);
AddMeasure(newMeasure);
if (other.referenceMeasure == otherCm) {
SetRefMeasure(newMeasure);
}
}
id = other.id;
chooserName = other.chooserName;
dateTime = other.dateTime;
type = other.type;
invalid = other.invalid;
editLock = other.editLock;
jigsawRejected = other.jigsawRejected;
referenceExplicitlySet = other.referenceExplicitlySet;
ignore = other.ignore;
aprioriSurfacePointSource = other.aprioriSurfacePointSource;
aprioriSurfacePointSourceFile = other.aprioriSurfacePointSourceFile;
aprioriRadiusSource = other.aprioriRadiusSource;
aprioriRadiusSourceFile = other.aprioriRadiusSourceFile;
aprioriSurfacePoint = other.aprioriSurfacePoint;
adjustedSurfacePoint = other.adjustedSurfacePoint;
numberOfRejectedMeasures = other.numberOfRejectedMeasures;
constraintStatus = other.constraintStatus;
}
/**
* Construct a control point with given Id
*
* @param id Control Point Id
*/
ControlPoint::ControlPoint(const QString &newId) : invalid(false) {
parentNetwork = NULL;
measures = NULL;
referenceMeasure = NULL;
numberOfRejectedMeasures = 0;
measures = new QHash< QString, ControlMeasure * >;
cubeSerials = new QStringList;
id = newId;
type = Free;
editLock = false;
jigsawRejected = false;
referenceExplicitlySet = false;
ignore = false;
aprioriSurfacePointSource = SurfacePointSource::None;
aprioriRadiusSource = RadiusSource::None;
constraintStatus.reset();
}
/**
* This destroys the current instance and cleans up any and all allocated
* memory.
*/
ControlPoint::~ControlPoint() {
if (measures != NULL) {
QList< QString > keys = measures->keys();
for (int i = 0; i < keys.size(); i++) {
delete(*measures)[keys[i]];
(*measures)[keys[i]] = NULL;
}
delete measures;
measures = NULL;
}
if (cubeSerials) {
delete cubeSerials;
cubeSerials = NULL;
}
referenceMeasure = NULL;
}
/**
* Loads the PvlObject into a ControlPoint
*
* @param p PvlObject containing ControlPoint information
* @param forceBuild Allows invalid Control Measures to be added to this
* Control Point
*
* @throws Isis::iException::User - Invalid Point Type
* @throws Isis::iException::User - Unable to add ControlMeasure to Control
* Point
*
* @history 2008-06-18 Tracie Sucharski/Jeannie Walldren, Fixed bug with
* checking for "True" vs "true", change to
* lower case for comparison.
* @history 2009-12-29 Tracie Sucharski - Added new ControlPoint information.
* @history 2010-01-13 Tracie Sucharski - Changed from Set methods to simply
* setting private variables to increase speed?
* @history 2010-07-30 Tracie Sucharski, Updated for changes made after
* additional working sessions for Control network
* design.
* @history 2010-09-01 Tracie Sucharski, Add checks for AprioriLatLonSource
* AprioriLatLonSourceFile. If there are
* AprioriSigmas,but no AprioriXYZ, use the XYZ values.
* @history 2010-09-15 Tracie Sucharski, It was decided after mtg with
* Debbie, Stuart, Ken and Tracie that ControlPoint
* will only function with x/y/z, not lat/lon/radius.
* It will be the responsibility of the application
* or class using ControlPoint to set up a
* SurfacePoint object to do conversions between x/y/z
* and lat/lon/radius.
* So... remove all conversion methods from this
* class.
* It was also decided that when importing old
* networks that contain Sigmas, the sigmas will not
* be imported , due to conflicts with the units of
* the sigmas,we cannot get accurate x,y,z sigmas from
* the lat,lon,radius sigmas without the covariance
* matrix.
* @history 2010-09-28 Tracie Sucharski, Added back the conversion methods
* from lat,lon,radius to x,y,z only for the point,
* since that is what most applications need.
* @history 2010-12-02 Debbie A. Cook, Added units to
* SurfacePoint.SetSpherical calls.
* @history 2011-03-12 Debbie A. Cook, Added targetRadius to do conversions
*/
void ControlPoint::Load(PvlObject &p) {
}
/**
* Add a measurement to the control point, taking ownership of the measure in
* the process.
*
* @param measure The ControlMeasure to add
*/
void ControlPoint::Add(ControlMeasure *measure) {
PointModified();
AddMeasure(measure);
}
/**
* Do the actual work of adding a measure to this point, without changing
* any extra data.
*/
void ControlPoint::AddMeasure(ControlMeasure *measure) {
// Make sure measure is unique
foreach(ControlMeasure * m, measures->values()) {
if (m->GetCubeSerialNumber() == measure->GetCubeSerialNumber()) {
QString msg = "The SerialNumber is not unique. A measure with "
"serial number [" + measure->GetCubeSerialNumber() + "] already "
"exists for ControlPoint [" + GetId() + "]";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
}
if (!measures->size()) {
ASSERT(!HasRefMeasure());
referenceMeasure = measure;
}
else if (referenceMeasure->IsIgnored() && !measure->IsIgnored() &&
!IsReferenceExplicit() && !IsEditLocked()) {
// The current "implicit" reference is ignored, but this new measure
// isn't, and the point is not edit locked, so make this measure the new
// reference
referenceMeasure = measure;
}
measure->parentPoint = this;
QString newSerial = measure->GetCubeSerialNumber();
measures->insert(newSerial, measure);
cubeSerials->append(newSerial);
// notify parent network if we have one
if (parentNetwork) {
parentNetwork->measureAdded(measure);
parentNetwork->emitNetworkStructureModified();
}
}
/**
* Throws an exception if none of the point's measures have the given serial
* number. It is common to ensure that a measure exists before taking some
* action.
*
* @param sn The serial number of the measure to validate
*/
void ControlPoint::ValidateMeasure(QString serialNumber) const {
if (!measures->contains(serialNumber)) {
QString msg = "No measure with serial number [" + serialNumber +
"] is owned by this point";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
}
/**
* Remove a measurement from the control point, deleting reference measure
* is allowed.
*
* @param serialNumber The serial number of the measure to delete
*/
int ControlPoint::Delete(QString serialNumber) {
ValidateMeasure(serialNumber);
ControlMeasure *cm = (*measures)[serialNumber];
// notify parent network of the change
if (parentNetwork) {
parentNetwork->measureDeleted(cm);
if (!IsIgnored() && !cm->IsIgnored()) {
parentNetwork->emitNetworkStructureModified();
}
}
if (cm->IsEditLocked()) {
return ControlMeasure::MeasureLocked;
}
// remove measure from the point's data structures
measures->remove(serialNumber);
cubeSerials->removeAt(cubeSerials->indexOf(serialNumber));
// update the reference measure
if (cubeSerials->size()) {
if (referenceMeasure == cm) {
referenceMeasure = (*measures)[cubeSerials->at(0)];
referenceExplicitlySet = false;
}
}
else {
referenceMeasure = NULL;
}
delete cm;
cm = NULL;
PointModified();
return ControlMeasure::Success;
}
/**
* This method is a wrapper to emit the measureModified() signal in the parent network
* is called whenever a change is made to a Control Measure.
*
* @param measure The ControlMeasure* that was modified.
* @param type The ControlMeasure::ModType indicating which modification occured.
* @param oldValue The oldValue before the change.
* @param newValue The new value that the change incorporated.
*/
void ControlPoint::emitMeasureModified(ControlMeasure *measure, ControlMeasure::ModType modType, QVariant oldValue, QVariant newValue) {
if (parentNetwork) {
parentNetwork->emitMeasureModified(measure, modType, oldValue, newValue);
}
}
/**
* Remove a measurement from the control point, deleting reference measure
* is allowed.
*
* @param measure The measure to delete
*/
int ControlPoint::Delete(ControlMeasure *measure) {
ASSERT(measure);
return Delete(measure->GetCubeSerialNumber());
}
/**
* Remove a measurement from the control point, deleting reference measure
* is allowed.
*
* @param index The index of the control measure to delete
*/
int ControlPoint::Delete(int index) {
if (index < 0 || index >= cubeSerials->size()) {
QString msg = "index [" + QString(index) + "] out of bounds";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
return Delete(cubeSerials->at(index));
}
/**
* Reset all the Apriori info to defaults
*
* @author Sharmila Prasad (10/22/2010)
*/
ControlPoint::Status ControlPoint::ResetApriori() {
if (IsEditLocked()) {
return PointLocked;
}
aprioriSurfacePointSource = SurfacePointSource::None;
aprioriSurfacePointSourceFile = "";
aprioriRadiusSource = RadiusSource::None;
aprioriRadiusSourceFile = "";
aprioriSurfacePoint = SurfacePoint();
constraintStatus.reset();
return Success;
}
/**
* Get a control measure based on its cube's serial number.
*
* @param serialNumber serial number of measure to get
* @returns control measure with matching serial number
*/
ControlMeasure *ControlPoint::GetMeasure(QString serialNumber) {
ValidateMeasure(serialNumber);
return (*measures)[serialNumber];
}
/**
* Get a control measure based on its cube's serial number.
*
* @param serialNumber serial number of measure to get
* @returns const control measure with matching serial number
*/
const ControlMeasure *ControlPoint::GetMeasure(QString serialNumber) const {
ValidateMeasure(serialNumber);
return measures->value(serialNumber);
}
const ControlMeasure *ControlPoint::GetMeasure(int index) const {
if (index < 0 || index >= cubeSerials->size()) {
QString msg = "Index [" + toString(index) + "] out of range";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
return GetMeasure(cubeSerials->at(index));
}
ControlMeasure *ControlPoint::GetMeasure(int index) {
if (index < 0 || index >= cubeSerials->size()) {
QString msg = "Index [" + toString(index) + "] out of range";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
return GetMeasure(cubeSerials->at(index));
}
/**
* Checks to see if a reference measure is set.
*
* @returns bool True if a reference measure is set.
*/
bool ControlPoint::HasRefMeasure() const {
return !(referenceMeasure == NULL);
}
/**
* Get the reference control measure.
*
* @returns const reference measure for this point
*/
const ControlMeasure *ControlPoint::GetRefMeasure() const {
if (!HasRefMeasure()) {
QString msg = "Control point [" + GetId() + "] has no reference measure!";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
return referenceMeasure;
}
/**
* Get the measure that is the reference directly.
*/
ControlMeasure *ControlPoint::GetRefMeasure() {
if (!HasRefMeasure()) {
QString msg = "Control point [" + GetId() + "] has no reference measure!";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
return referenceMeasure;
}
/**
* Set the point's chooser name. This will be lost if any attributes relating
* to this point is later changed and the current user will be set. This is
* one of the 'last modified attributes' referred to in other comments.
*
* @param name The username of the person who last modified this control point
*/
ControlPoint::Status ControlPoint::SetChooserName(QString name) {
if (editLock) {
return PointLocked;
}
chooserName = name;
return Success;
}
/**
* Set the point's last modified time. This will be lost if any attributes
* relating to this point are later changed and the current time will be
* set. This is one of the 'last modified attributes' referred to in other
* comments.
*
* @param newDateTime The date and time this control point was last modified
*/
ControlPoint::Status ControlPoint::SetDateTime(QString newDateTime) {
if (editLock) {
return PointLocked;
}
dateTime = newDateTime;
return Success;
}
/**
* Set the EditLock state. If edit lock is on, then most attributes relating
* to this point are not modifiable. Edit lock is like "Don't modify my
* attributes, but you can still modify my measures' attributes". The
* reference measure is implicitely edit locked if the point is edit locked.
*
* @param lock True to enable edit lock, false to disable it and allow the
* point to be modified.
*/
ControlPoint::Status ControlPoint::SetEditLock(bool lock) {
if (parentNetwork) {
parentNetwork->emitPointModified(this, ControlPoint::EditLockModified, editLock, lock);
}
editLock = lock;
return Success;
}
/**
* Set the jigsawRejected state. If IsRejected is true, then this point should be
* ignored until the next iteration in the bundle adjustement. BundleAdjust
* decides when to reject or accept a point. The initial IsRejected state of
* a measure is false.
*
* @param reject True to reject a measure, false to include it in the adjustment
*/
ControlPoint::Status ControlPoint::SetRejected(bool reject) {
jigsawRejected = reject;
return Success;
}
/**
* Sets the Id of the control point
*
* @param id Control Point Id
*
* @return (int) status Success or PointLocked
*/
ControlPoint::Status ControlPoint::SetId(QString newId) {
if (editLock) {
return PointLocked;
}
QString oldId = id;
id = newId;
if (parentNetwork) {
parentNetwork->UpdatePointReference(this, oldId);
}
return Success;
}
/**
* Set the point's reference measure
*
* @param cm The new reference measure
*/
ControlPoint::Status ControlPoint::SetRefMeasure(ControlMeasure *cm) {
if (editLock) {
return PointLocked;
}
ASSERT(cm);
SetExplicitReference(cm);
return Success;
}
/**
* Set the point's reference measure
*
* @param index The index of the new reference measure
*/
ControlPoint::Status ControlPoint::SetRefMeasure(int index) {
if (editLock) {
return PointLocked;
}
if (index < 0 || index >= cubeSerials->size()) {
QString msg = "Index [";
msg += toString(index) + "] out of range";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
SetExplicitReference((*measures)[cubeSerials->at(index)]);
return Success;
}
/**
* Set the points reference measure
*
* @param sn The serial number of the new reference measure
*/
ControlPoint::Status ControlPoint::SetRefMeasure(QString sn) {
if (editLock) {
return PointLocked;
}
if (!cubeSerials->contains(sn)) {
QString msg = "Point [" + id + "] has no measure with serial number [" +
sn + "]";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
SetExplicitReference((*measures)[sn]);
return Success;
}
/**
* Explicitly defines a new reference measure by pointer. This assumes the
* point already has ownership over this pointer. As part of the explicit
* definition process, the reference will attempt to be made ignored if the
* measure will allow it.
*
* In the past, setting an explicit reference would also attempt to set the
* new reference to un-ignored (this would only fail if the measure was "Edit
* Locked"). This blanket rule was removed, however, because the bundle
* adjustment processing phase could often intentionally set references to
* ignored, and in some instances (e.g., merging a partial network back into
* the base network) this rule would mistakenly set those properly ignored
* references back to un-ignored. While this rule made sense for the
* registration phase of processing, it clearly caused problems during bundle
* adjustment and merging.
*
* @param measure The new reference measure
*/
void ControlPoint::SetExplicitReference(ControlMeasure *measure) {
referenceExplicitlySet = true;
referenceMeasure = measure;
}
/**
* Set whether to ignore or use control point
*
* @param newIgnoreStatus True to ignore this Control Point, False to
* un-ignore
*/
ControlPoint::Status ControlPoint::SetIgnored(bool newIgnoreStatus) {
if (editLock) {
return PointLocked;
}
bool oldStatus = ignore;
ignore = newIgnoreStatus;
// only update if there was a change in status
if (oldStatus != ignore) {
PointModified();
if (parentNetwork) {
if (ignore) {
parentNetwork->pointIgnored(this);
}
else {
parentNetwork->pointUnIgnored(this);
}
parentNetwork->emitPointModified(this, ControlPoint::IgnoredModified, oldStatus, ignore);
}
}
return Success;
}
/**
* Set or update the surface point relating to this control point. This is
* the point on the surface of the planet that the measures are tied to.
* This updates the last modified attributes of this point.
* *** Warning: Only BundleAdjust and its applications should be
* using this method.
*
* @param newSurfacePoint The point on the target's surface the measures are
* tied to
*
* @internal
* @history 2011-07-01 Debbie A. Cook Removed editLock check
*/
ControlPoint::Status ControlPoint::SetAdjustedSurfacePoint(
SurfacePoint newSurfacePoint) {
PointModified();
adjustedSurfacePoint = newSurfacePoint;
return Success;
}
/**
* Updates the control point's type. This updates the last modified attributes
* of this point.
*
* @see PointType
*
* @param newType The new type this control point should be
*/
ControlPoint::Status ControlPoint::SetType(PointType newType) {
if (type != Fixed && type != Free && type != Constrained) {
QString msg = "Invalid Point Enumeration, [" + QString(type) + "], for "
"Control Point [" + GetId() + "]";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
if (editLock) {
return PointLocked;
}
if (parentNetwork) {
parentNetwork->emitPointModified(this, ControlPoint::TypeModified, type, newType);
}
PointModified();
type = newType;
return Success;
}
/**
* This updates the source of the radius of the apriori surface point.
*
* @see RadiusSource::Source
*
* @param source Where the radius came from
*/
ControlPoint::Status ControlPoint::SetAprioriRadiusSource(
RadiusSource::Source source) {
if (editLock) {
return PointLocked;
}
PointModified();
aprioriRadiusSource = source;
return Success;
}
/**
* This updates the filename of the DEM that the apriori radius came from. It
* doesn't really make sense to call this unless the RadiusSource is DEM.
*
* @see RadiusSource::Source
*
* @param source Where the radius came from
*/
ControlPoint::Status ControlPoint::SetAprioriRadiusSourceFile(
QString sourceFile) {
if (editLock) {
return PointLocked;
}
PointModified();
aprioriRadiusSourceFile = sourceFile;
return Success;
}
/**
* This updates the apriori surface point.
*
* @see SetAprioriRadiusSource
* @see SetAprioriRadiusSourceFile
* @see SetAprioriPointSource
* @see SetAprioriPointSourceFile
* @see aprioriSurfacePoint
*
* @param aprioriSP The apriori surface point to remember
* @todo This method needs to be revisited. It will set the constraint
* status based on the sigmas and override the existing status.
*/
ControlPoint::Status ControlPoint::SetAprioriSurfacePoint(
SurfacePoint aprioriSP) {
SurfacePoint::CoordinateType coordType = SurfacePoint::Latitudinal;
if (parentNetwork) {
coordType = parentNetwork->GetCoordType();
}
if (editLock) {
return PointLocked;
}
// ***TBD*** Does it make sense to try to do a generic check here? The
// data types are different (angles vs distance) so for now do a switch.
switch (coordType) {
case SurfacePoint::Latitudinal:
if (aprioriSP.GetLatSigma().isValid())
constraintStatus.set(Coord1Constrained);
if (aprioriSP.GetLonSigma().isValid())
constraintStatus.set(Coord2Constrained);
if (aprioriSP.GetLocalRadiusSigma().isValid())
constraintStatus.set(Coord3Constrained);
break;
case SurfacePoint::Rectangular:
if (aprioriSP.GetXSigma().isValid())
constraintStatus.set(Coord1Constrained);
if (aprioriSP.GetYSigma().isValid())
constraintStatus.set(Coord2Constrained);
if (aprioriSP.GetZSigma().isValid())
constraintStatus.set(Coord3Constrained);
}
PointModified();
aprioriSurfacePoint = aprioriSP;
return Success;
}
/**
* This updates the source of the surface point
*
* @see SurfacePointSource::Source
*
* @param source Where the surface point came from
*/
ControlPoint::Status ControlPoint::SetAprioriSurfacePointSource(
SurfacePointSource::Source source) {
if (editLock) {
return PointLocked;
}
PointModified();
aprioriSurfacePointSource = source;
return Success;
}
/**
* This updates the filename of where the apriori surface point came from.
*
* @see RadiusSource::Source
*
* @param sourceFile Where the surface point came from
*/
ControlPoint::Status ControlPoint::SetAprioriSurfacePointSourceFile(
QString sourceFile) {
if (editLock) {
return PointLocked;
}
PointModified();
aprioriSurfacePointSourceFile = sourceFile;
return Success;
}
/**
* Computes a priori lat/lon/radius point coordinates by determining the average lat/lon/radius of
* all measures. Note that this does not change ignored, fixed or constrained points.
*
* Also, it does not use unmeasured or ignored measures when computing lat/lon/radius.
*
* (KLE) Note this not a rigorous triangulation considering outliers. A better way would be to...
* a) use e.g. a closest approach algorithm to find intersection of all rays, regardless
* of whether the intersection lies on the surface in question, then;
* b) perform a rigorous triangulation with some sort outlier detection approach, a robust
* estimation technique (perhaps RANSAC)
*
* @internal
* @history 2008-06-18 Tracie Sucharski/Jeannie Walldren,
* Changed error messages for
* Held/Ground points.
* @history 2009-10-13 Jeannie Walldren - Added detail to
* error message.
* @history 2010-11-29 Tracie Sucharski - Remove call to ControlMeasure::
* SetMeasuredEphemerisTime, the values were
* never used. so these methods were removed
* from ControlMeasure and the call was removed
* here.
* @history 2010-12-02 Debbie A. Cook - Added units to SetRectangular
* calls since default is meters and units
* are km.
* @history 2011-03-17 Debbie A. Cook - Added initialization of
* adjustedSurfacePoint to aprioriSurfacePoint
* and set test for empty covariance matrix
* to use 0. instead of nulls.
* @history 2011-03-24 Debbie A. Cook - Removed IsMeasured check since it
* was really checking for Candidate measures.
* @history 2011-07-12 Debbie A. Cook - Removed editLock test. Users agreed
* editLock was only for fixed and constrained
* points, which are already left unchanged by
* ComputeApriori. If a free point is editLocked
* the editLock will be ignored by this method.
* @history 2017-04-25 Debbie A. Cook - change constraint status calls
* to use generic coordinate names (Coord1, Coord2,
* and Coord3).
* @history 2019-03-10 Ken Edmundson - Fixed bug where focal plane measured x,y coordinates were
* not set if the cam->SetImage call failed. Setting the measured
* focal plane coordinates should not depend upon the success of the
* SetImage call (References #2591). Improved error messages.
* Cleaned up code. Added comments above to suggest a more rigorous
* approach to computing a priori point coordinates.
*
* @return Status Success or PointLocked
*/
ControlPoint::Status ControlPoint::ComputeApriori() {
// TODO (KLE): where should call this go? Also, what's the point? The method has no description.
PointModified();
// if point is fixed or constrained, ensure valid a priori point coordinates exist
if ( (IsFixed() || IsConstrained()) && !aprioriSurfacePoint.Valid() ) {
QString msg = "In method ControlPoint::ComputeApriori(). ControlPoint [" + GetId() + "] is ";
msg += "fixed or constrained and requires a priori coordinates";
throw IException(IException::User, msg, _FILEINFO_);
}
double xB = 0.0; // body-fixed x
double yB = 0.0; // body-fixed y
double zB = 0.0; // body-fixed z
double r2B = 0.0; // radius squared in body-fixed
int goodMeasures = 0;
double pB[3];
bool computeApriori = false;
// loop over measures to ...
// 1) set focal plane x,y coordinates for all unignored measures;
// 2) sum latitude, longitude, and radius coordinates in preparation for computing a priori
// coordinates by averaging.
for (int i = 0; i < cubeSerials->size(); i++) {
ControlMeasure *m = GetMeasure(i);
if (m->IsIgnored()) {
continue;
}
Camera *cam = m->Camera();
if (cam == NULL) {
QString cubeSN = m->GetCubeSerialNumber();
QString msg = "in method ControlPoint::ComputeApriori(). Camera has not been set in ";
msg += "measure for cube serial number [" + cubeSN + "], Control Point id ";
msg += "[" + GetId() + "]. Camera must be set prior to calculating a priori coordinates";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
bool setImageSuccess = cam->SetImage(m->GetSample(), m->GetLine());
m->SetFocalPlaneMeasured(cam->DistortionMap()->UndistortedFocalPlaneX(),
cam->DistortionMap()->UndistortedFocalPlaneY());
// TODO: Seems like we should be able to skip this computation if point is fixed or
// constrained in any coordinate. Currently we are always summing coordinates here. We could
// save time by not doing this for fixed or constrained points.
if (!IsFixed() && !IsConstrained() && !id.contains("Lidar")) {
computeApriori = true;
if (setImageSuccess) {
goodMeasures++;
cam->Coordinate(pB);
xB += pB[0];
yB += pB[1];
zB += pB[2];
r2B += pB[0]*pB[0] + pB[1]*pB[1] + pB[2]*pB[2];
}
}
}
// if we don't have to compute the a priori coordinates, i.e.
// if point is Fixed or Constrained in any number of coordinates, or is a lidar point,
// then just initialize adjustedSurfacePoint to a priori coordinates (set in e.g. qnet or
// cneteditor) and exit
if (!computeApriori) {
adjustedSurfacePoint = aprioriSurfacePoint;
return Success;
}
// if point is Free, we continue to compute a priori coordinates
// if no good measures, we're done
// TODO: is the message true/meaningful?
if (goodMeasures == 0) {
QString msg = "in method ControlPoint::ComputeApriori(). ControlPoint [" + GetId() + "] has ";
msg += "no measures which project to the body";
throw IException(IException::User, msg, _FILEINFO_);
// adjustedSurfacePoint = aprioriSurfacePoint;
// return Success;
}
// Compute the averages if all coordinates are free
// TODO: confirm if this "if" statement is necessary
if (GetType() == Free || NumberOfConstrainedCoordinates() == 0) {
double avgX = xB / goodMeasures;
double avgY = yB / goodMeasures;
double avgZ = zB / goodMeasures;
double avgR2 = r2B / goodMeasures;
double scale = sqrt(avgR2/(avgX*avgX+avgY*avgY+avgZ*avgZ));
aprioriSurfacePoint.SetRectangular(
Displacement((avgX*scale), Displacement::Kilometers),
Displacement((avgY*scale), Displacement::Kilometers),
Displacement((avgZ*scale), Displacement::Kilometers));
}
adjustedSurfacePoint = aprioriSurfacePoint;
SetAprioriSurfacePointSource(SurfacePointSource::AverageOfMeasures);
SetAprioriRadiusSource(RadiusSource::AverageOfMeasures);
return Success;
}
/**
* This method computes the BundleAdjust residuals for a point.
* *** Warning: Only BundleAdjust and its applications should be
* using this method.
*
* @history 2008-07-17 Tracie Sucharski, Added ptid and measure serial
* number to the unable to map to surface error.
* @history 2009-12-06 Tracie Sucharski, Renamed from ComputeErrors
* @history 2010-08-05 Tracie Sucharski, Changed lat/lon/radius to x/y/z
* @history 2010-12-10 Debbie A. Cook, Revised error calculation for radar
* because it was always reporting line errors=0.
* @history 2011-03-17 Debbie A. Cook, Fixed typo in radar call to get
* longitude
* @history 2011-03-24 Debbie A. Cook, Removed IsMeasured check since it
* was really checking for Candidate measures.
* @history 2011-07-01 Debbie A. Cook, Removed editLock check to allow
* BundleAdjust to compute residuals for
* editLocked points
* @history 2012-01-18 Debbie A. Cook, Revised to call
* ComputeResidualsMillimeters() to avoid
* duplication of code
* @history 2018-06-13 Debbie A. Cook, Ken Edmundson, Removed method ComputeResidualsMillimeters()
* and the call to it that was in this method. Added computation of
* focal plane computedx and computedy here.
*/
ControlPoint::Status ControlPoint::ComputeResiduals() {
if (IsIgnored()) {
return Failure;
}
PointModified();
double cuSamp, cuLine;
double muSamp, muLine;
double cudx = 0.0;
double cudy = 0.0;
// Loop for each measure to compute the error
QList<QString> keys = measures->keys();
for (int j = 0; j < keys.size(); j++) {
ControlMeasure *m = (*measures)[keys[j]];
if (m->IsIgnored()) {
continue;
}
// The following lines actually check for Candidate measures
// Commented out on 2011-03-24 by DAC
// if (!m->IsMeasured()) {
// continue;
Camera *cam = m->Camera();
CameraFocalPlaneMap *fpmap = cam->FocalPlaneMap();
// Map the lat/lon/radius of the control point through the Spice of the
// measurement sample/line to get the computed undistorted focal plane
// coordinates (mm if not radar). This works for radar too because in
// the undistorted focal plane, y has not been set to 0 (set to 0 when
// going to distorted focal plane or ground range in this case), so we
// can hold the Spice to calculate residuals in undistorted focal plane
// coordinates.
if (cam->GetCameraType() != 0) { // no need to call setimage for framing camera
cam->SetImage(m->GetSample(), m->GetLine());
}
// cam->GroundMap()->GetXY(GetAdjustedSurfacePoint(), &cudx, &cudy);
cam->GroundMap()->GetXY(adjustedSurfacePoint, &cudx, &cudy);
m->SetFocalPlaneComputed(cudx, cudy);
// TODO:TESTING
// cam->DistortionMap()->SetUndistortedFocalPlane(cudx,cudy);
// double distortedx = cam->DistortionMap()->FocalPlaneX();
// double distortedy = cam->DistortionMap()->FocalPlaneY();
// fpmap->SetFocalPlane(distortedx, distortedy);
// double distortedsample = fpmap->DetectorSample();
// double distortedline = fpmap->DetectorLine();
// TODO:TESTING
if (cam->GetCameraType() != Isis::Camera::Radar) {
// Now things get tricky. We want to produce errors in pixels not mm
// but some of the camera maps could fail. One that won't is the
// FocalPlaneMap which takes x/y to detector s/l. We will bypass the
// distortion map and have residuals in undistorted pixels.
if (!fpmap->SetFocalPlane(cudx, cudy)) {
QString msg = "Sanity check #1 for ControlPoint [" + GetId() +
"], ControlMeasure [" + m->GetCubeSerialNumber() + "]";
throw IException(IException::Programmer, msg, _FILEINFO_);
// This error shouldn't happen but check anyways
}
cuSamp = fpmap->DetectorSample();
cuLine = fpmap->DetectorLine();
}
else {
// For radar line is calculated from time in the camera. Use the
// closest line to scale the focal plane y (doppler shift) to image line
// for computing the line residual. Get a local ratio
// measureLine = adjacentLine
// ------------ -------------- in both cases, doppler shift
// dopplerMLine dopplerAdjLine is calculated using SPICE
// at the time of the measurement
//
// 1. Get the surface point mapped to by an adjacent pixel above (if
// doppler is < 0) or below (if doppler is > 0) the measured pixel
// 2. Set image to the measured sample/line to load the SPICE for the
// time of the measurement.
// 3. Map the surface point from the adjacent pixel through the SPICE
// into the image plane to get a scale for mapping from doppler
// shift to line. Apply the scale to get the line residual
double sample = m->GetSample();
double computedY = m->GetFocalPlaneComputedY();
double computedX = m->GetFocalPlaneComputedX();
double adjLine;
// Step 1. What happens if measured line is 1??? TODO
if (computedY < 0) {
adjLine = m->GetLine() - 1.;
}
else {
adjLine = m->GetLine() + 1.;
}
cam->SetImage(sample, adjLine);
SurfacePoint sp = cam->GetSurfacePoint();
// Step 2.
cam->SetImage(sample, m->GetLine());
double focalplaneX;
double scalingY;
// Step 3.
cam->GroundMap()->GetXY(sp, &focalplaneX, &scalingY);
double deltaLine;
if (computedY < 0) {
deltaLine = -computedY/scalingY;
}
else {
deltaLine = computedY/scalingY;
}
// Now map through the camera steps to take X from slant range to ground
// range to pixels. Y just tracks through as 0.
if (cam->DistortionMap()->SetUndistortedFocalPlane(computedX,
computedY)){
double focalPlaneX = cam->DistortionMap()->FocalPlaneX();
double focalPlaneY = cam->DistortionMap()->FocalPlaneY();
fpmap->SetFocalPlane(focalPlaneX,focalPlaneY);
}
cuSamp = fpmap->DetectorSample();
cuLine = m->GetLine() + deltaLine;
}
if (cam->GetCameraType() != Isis::Camera::Radar) {
// Again we will bypass the distortion map and have residuals in undistorted pixels.
if (!fpmap->SetFocalPlane(m->GetFocalPlaneMeasuredX(), m->GetFocalPlaneMeasuredY())) {
QString msg = "Sanity check #2 for ControlPoint [" + GetId() +
"], ControlMeasure [" + m->GetCubeSerialNumber() + "]";
throw IException(IException::Programmer, msg, _FILEINFO_);
// This error shouldn't happen but check anyways
}
muSamp = fpmap->DetectorSample();
muLine = fpmap->DetectorLine();
}
else {
muSamp = m->GetSample();
muLine = m->GetLine();
}
// The units are in detector sample/lines. We will apply the instrument
// summing mode to get close to real pixels. Note however we are in
// undistorted pixels except for radar instruments.
double sampResidual = muSamp - cuSamp;
double lineResidual = muLine - cuLine;
// TODO: TESTING
// double x = cam->DistortionMap()->FocalPlaneX();
// double y = cam->DistortionMap()->FocalPlaneY();
// m->SetFocalPlaneMeasured(x, y);
// double mdissamp = fpmap->DetectorSample();
// double mdisline = fpmap->DetectorLine();
// double distortedSampleResidual = fpmap->DetectorSample() - distortedsample;
// double distortedLineResidual = fpmap->DetectorLine() - distortedline;
// TODO: TESTING
m->SetResidual(sampResidual, lineResidual);
}
return Success;
}
QString ControlPoint::GetChooserName() const {
if (chooserName != "") {
return chooserName;
}
else {
return FileName(Application::Name()).name();
}
}
//! Returns true if the choosername is not empty.
bool ControlPoint::HasChooserName() const {
return !chooserName.isEmpty();
}
//! Returns true if the datetime is not empty.
bool ControlPoint::HasDateTime() const {
return !dateTime.isEmpty();
}
QString ControlPoint::GetDateTime() const {
if (dateTime != "") {
return dateTime;
}
else {
return Application::DateTime();
}
}
bool ControlPoint::IsEditLocked() const {
return editLock;
}
bool ControlPoint::IsRejected() const {
return jigsawRejected;
}
SurfacePoint ControlPoint::GetAdjustedSurfacePoint() const {
return adjustedSurfacePoint;
}
/**
* Returns the adjusted surface point if it exists, otherwise returns
* the a priori surface point.
*/
SurfacePoint ControlPoint::GetBestSurfacePoint() const {
if (adjustedSurfacePoint.Valid()) {
return adjustedSurfacePoint;
}
else {
return aprioriSurfacePoint;
}
}
/**
* Return the Id of the control point
*
* @return Control Point Id
*/
QString ControlPoint::GetId() const {
return id;
}
bool ControlPoint::IsIgnored() const {
return ignore;
}
bool ControlPoint::IsValid() const {
return !invalid;
}
bool ControlPoint::IsInvalid() const {
return invalid;
}
/**
* Obtain a string representation of a given PointType
*
* @param type PointType to convert to a string
*
* @returns A string representation of type
*/
QString ControlPoint::PointTypeToString(PointType pointType) {
QString str;
switch (pointType) {
case Fixed:
str = "Fixed";
break;
case Constrained:
str = "Constrained";
break;
case Free:
str = "Free";
break;
}
return str;
}
/**
* Obtain a PointType given a string representation of it.
*
* @param pointTypeString for the requested PointType
*
* @returns the PointType for the given string
*/
ControlPoint::PointType ControlPoint::StringToPointType(
QString pointTypeString) {
// On failure assume Free
ControlPoint::PointType type = ControlPoint::Free;
QString errMsg = "There is no PointType that has a string representation"
" of \"";
errMsg += pointTypeString;
errMsg += "\".";
if (pointTypeString == "Fixed") {
type = ControlPoint::Fixed;
}
else if (pointTypeString == "Constrained") {
type = ControlPoint::Constrained;
}
else if (pointTypeString == "Free") {
type = ControlPoint::Free;
}
else {
throw IException(IException::Programmer, errMsg, _FILEINFO_);
}
return type;
}
/**
* Obtain a string representation of the PointType
*
* @return A string representation of the PointType
*/
QString ControlPoint::GetPointTypeString() const {
return PointTypeToString(GetType());
}
/**
* @returns this point't type
*
*/
ControlPoint::PointType ControlPoint::GetType() const {
return type;
}
/**
* Obtain a string representation of a given RadiusSource
*
* @param source RadiusSource to convert to string
*
* @returns A string representation of RadiusSource
*/
QString ControlPoint::RadiusSourceToString(RadiusSource::Source source) {
QString str;
switch (source) {
case RadiusSource::None:
str = "None";
break;
case RadiusSource::User:
str = "User";
break;
case RadiusSource::AverageOfMeasures:
str = "AverageOfMeasures";
break;
case RadiusSource::Ellipsoid:
str = "Ellipsoid";
break;
case RadiusSource::DEM:
str = "DEM";
break;
case RadiusSource::BundleSolution:
str = "BundleSolution";
break;
}
return str;
}
/**
* Obtain a RadiusSource::Source from a string
*
* @param str string to get a RadiusSource::Source from
*
* @returns The RadiusSource::Source matching the given string
*/
ControlPoint::RadiusSource::Source ControlPoint::StringToRadiusSource(
QString str) {
str = str.toLower();
RadiusSource::Source source = RadiusSource::None;
if (str == "user") {
source = RadiusSource::User;
}
else if (str == "averageofmeasures") {
source = RadiusSource::AverageOfMeasures;
}
else if (str == "ellipsoid") {
source = RadiusSource::Ellipsoid;
}
else if (str == "dem") {
source = RadiusSource::DEM;
}
else if (str == "bundlesolution") {
source = RadiusSource::BundleSolution;
}
return source;
}
/**
* Obtain a string representation of the RadiusSource
*
* @return A string representation of the RadiusSource
*/
QString ControlPoint::GetRadiusSourceString() const {
return RadiusSourceToString(aprioriRadiusSource);
}
/**
* Obtain a string representation of a given SurfacePointSource
*
* @param souce SurfacePointSource to get a string representation of
*
* @returns A string representation of SurfacePointSource
*/
QString ControlPoint::SurfacePointSourceToString(
SurfacePointSource::Source source) {
QString str;
switch (source) {
case SurfacePointSource::None:
str = "None";
break;
case SurfacePointSource::User:
str = "User";
break;
case SurfacePointSource::AverageOfMeasures:
str = "AverageOfMeasures";
break;
case SurfacePointSource::Reference:
str = "Reference";
break;
case SurfacePointSource::Basemap:
str = "Basemap";
break;
case SurfacePointSource::BundleSolution:
str = "BundleSolution";
break;
}
return str;
}
/**
* Obtain a SurfacePoint::Source from a string
*
* @param str string to get a SurfacePoint::Source from
*
* @returns The SurfacePint::Source matching the given string
*/
ControlPoint::SurfacePointSource::Source
ControlPoint::StringToSurfacePointSource(
QString str) {
str = str.toLower();
SurfacePointSource::Source source = SurfacePointSource::None;
if (str == "user") {
source = SurfacePointSource::User;
}
else if (str == "averageofmeasures") {
source = SurfacePointSource::AverageOfMeasures;
}
else if (str == "reference") {
source = SurfacePointSource::Reference;
}
else if (str == "basemap") {
source = SurfacePointSource::Basemap;
}
else if (str == "bundlesolution") {
source = SurfacePointSource::BundleSolution;
}
return source;
}
/**
* Obtain a string representation of the SurfacePointSource
*
* @return A string representation of the SurfacePointSource
*/
QString ControlPoint::GetSurfacePointSourceString() const {
return SurfacePointSourceToString(aprioriSurfacePointSource);
}
bool ControlPoint::IsFixed() const {
return (type == Fixed);
}
SurfacePoint ControlPoint::GetAprioriSurfacePoint() const {
return aprioriSurfacePoint;
}
ControlPoint::RadiusSource::Source ControlPoint::GetAprioriRadiusSource()
const {
return aprioriRadiusSource;
}
bool ControlPoint::HasAprioriCoordinates() {
if (aprioriSurfacePoint.GetX().isValid() &&
aprioriSurfacePoint.GetY().isValid() &&
aprioriSurfacePoint.GetZ().isValid()) {
return true;
}
return false;
// return aprioriSurfacePoint.Valid(); ???
}
bool ControlPoint::IsConstrained() {
return constraintStatus.any();
}
bool ControlPoint::IsCoord1Constrained() {
return constraintStatus[Coord1Constrained];
}
bool ControlPoint::IsCoord2Constrained() {
return constraintStatus[Coord2Constrained];
}
bool ControlPoint::IsCoord3Constrained() {
return constraintStatus[Coord3Constrained];
}
int ControlPoint::NumberOfConstrainedCoordinates() {
return constraintStatus.count();
}
/**
* Checks to see if the radius source file has been set.
*
* @return bool True if the radius source file has been set.
*/
bool ControlPoint::HasAprioriRadiusSourceFile() const {
return !( aprioriRadiusSourceFile.isEmpty() || aprioriRadiusSourceFile.isNull() );
}
QString ControlPoint::GetAprioriRadiusSourceFile() const {
return aprioriRadiusSourceFile;
}
ControlPoint::SurfacePointSource::Source
ControlPoint::GetAprioriSurfacePointSource() const {
return aprioriSurfacePointSource;
}
/**
* Checks to see if the surface point source file has been set.
*
* @return bool True if the surface point source file has been set.
*/
bool ControlPoint::HasAprioriSurfacePointSourceFile() const {
return !( aprioriSurfacePointSourceFile.isEmpty() || aprioriSurfacePointSourceFile.isNull() );
}
QString ControlPoint::GetAprioriSurfacePointSourceFile() const {
return aprioriSurfacePointSourceFile;
}
int ControlPoint::GetNumMeasures() const {
return measures->size();
}
/**
*
* @return Number of valid control measures
*/
int ControlPoint::GetNumValidMeasures() const {
int size = 0;
QList<QString> keys = measures->keys();
for (int cm = 0; cm < keys.size(); cm++) {
if (!(*measures)[keys[cm]]->IsIgnored()) {
size++;
}
}
return size;
}
/**
* Returns the number of locked control measures
*
* @return Number of locked control measures
*/
int ControlPoint::GetNumLockedMeasures() const {
int size = 0;
QList<QString> keys = measures->keys();
for (int cm = 0; cm < keys.size(); cm++) {
if ((*measures)[keys[cm]]->IsEditLocked()) {
size++;
}
}
return size;
}
/**
* Return true if given serial number exists in point
*
* @param serialNumber The serial number
* @return True if point contains serial number, false if not
*/
bool ControlPoint::HasSerialNumber(QString serialNumber) const {
return cubeSerials->contains(serialNumber);
}
/**
* @returns true Returns true if SetRefMeasure has ever been set on this
* point.
*/
bool ControlPoint::IsReferenceExplicit() const {
return referenceExplicitlySet;
}
/**
* @returns The cube serial number of the reference measure
*/
QString ControlPoint::GetReferenceSN() const {
if (!HasRefMeasure()) {
QString msg = "There is no reference measure set in the ControlPoint [" +
GetId() + "]";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
return referenceMeasure->GetCubeSerialNumber();
}
/**
* @param cm The control measure to find the index of
* @param throws Throws an exception on failure instead of returning -1.
* Be aware that by default this is true!
*
* @returns The index of the passed in measure, or -1 on failure if throws
* is false.
*/
int ControlPoint::IndexOf(ControlMeasure *cm, bool throws) const {
ASSERT(cm);
return IndexOf(cm->GetCubeSerialNumber(), throws);
}
/**
* @param sn The serial number of the control measure to find the index of
* @param throws Throws an exception on failure instead of returning -1.
* Be aware that by default this is true!
*
* @returns The index of the measure with serial number matching sn,
* or -1 on failure if throws is false.
*/
int ControlPoint::IndexOf(QString sn, bool throws) const {
int index = cubeSerials->indexOf(sn);
if (throws && index == -1) {
QString msg = "ControlMeasure [" + sn + "] does not exist in point [" +
id + "]";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
return index;
}
/**
* @param throws Throws an exception on failure instead of returning -1.
* Be aware that by default this is true!
*
* @returns The index of the reference measure, or -1 if no measures exist
* in the point (A point with at least one measure ALWAYS has a reference
* measure.
*/
int ControlPoint::IndexOfRefMeasure() const {
if (!HasRefMeasure()) {
QString msg = "There is no reference measure for point [" + id + "]."
" This also means of course that the point is empty!";
throw IException(IException::Programmer, msg, _FILEINFO_);
}
int index = cubeSerials->indexOf(referenceMeasure->GetCubeSerialNumber());
ASSERT(index != -1)
return index;
}
/**
* This function will call a given method on every control measure that
* this point has.
*
* @param statFunc The function to use for data collection
*
* @returns The gathered statistic
*
* @history 2011-03-08 Debbie A. Cook - Changed to get statistics for all
* point types and not just Candidate.
*/
Statistics ControlPoint::GetStatistic(
double(ControlMeasure::*statFunc)() const) const {
Statistics stats;
foreach(ControlMeasure * cm, *measures) {
if (!cm->IsIgnored()) {
stats.AddData((cm->*statFunc)());
}
}
return stats;
}
Statistics ControlPoint::GetStatistic(long dataType) const {
Statistics stats;
foreach(ControlMeasure * cm, *measures) {
if (!cm->IsIgnored()) {
stats.AddData(cm->GetLogData(dataType).GetNumericalValue());
}
}
return stats;
}
/**
* @param excludeIgnored Ignored measures are excluded if this is true. It
* is false by default.
*
* @returns A list of this points measures
*/
QList< ControlMeasure * > ControlPoint::getMeasures(
bool excludeIgnored) const {
QList< ControlMeasure * > orderedMeasures;
for (int i = 0; i < cubeSerials->size(); i++) {
ControlMeasure *measure = measures->value((*cubeSerials)[i]);
if (!excludeIgnored || !measure->IsIgnored()) {
orderedMeasures.append(measures->value((*cubeSerials)[i]));
}
}
return orderedMeasures;
}
/**
* @returns A list of cube serial numbers
*/
QList< QString > ControlPoint::getCubeSerialNumbers() const {
return *cubeSerials;
}
/**
* Same as GetMeasure (provided for convenience)
*
* @param serialNumber Cube serial number of desired control measure
*
* @returns const version of the measure which has the provided serial number
*/
const ControlMeasure *ControlPoint::operator[](QString serialNumber) const {
return GetMeasure(serialNumber);
}
/**
* Same as GetMeasure (provided for convenience)
*
* @param serialNumber Cube serial number of desired control measure
*
* @returns The measure which has the provided serial number
*/
ControlMeasure *ControlPoint::operator[](QString serialNumber) {
return GetMeasure(serialNumber);
}
/**
* Same as GetMeasure (provided for convenience)
*
* @param index If there are n measures, the measure returned will be the
* ith measure added to the point
*
* @returns const version of the measure which has the provided serial number
*/
const ControlMeasure *ControlPoint::operator[](int index) const {
return GetMeasure(index);
}
/**
* Same as GetMeasure (provided for convenience)
*
* @param index If there are n measures, the measure returned will be the
* ith measure added to the point
*
* @returns The measure which has the provided serial number
*/
ControlMeasure *ControlPoint::operator[](int index) {
return GetMeasure(index);
}
/**
* Compare two Control Points for inequality
*
* @param other The other point to compare this one to
*
* @returns true if the two points are not equal, and false otherwise
*/
bool ControlPoint::operator!=(const ControlPoint &other) const {
return !(*this == other);
}
/**
* Compare two Control Points for equality
*
* @param other The other point to compare to
*
* @returns true if the two points are equal, and false otherwise
*
*/
bool ControlPoint::operator==(const ControlPoint &other) const {
return other.GetNumMeasures() == GetNumMeasures() &&
other.id == id &&
other.type == type &&
other.chooserName == chooserName &&
other.editLock == editLock &&
other.ignore == ignore &&
other.aprioriSurfacePointSource == aprioriSurfacePointSource &&
other.aprioriSurfacePointSourceFile == aprioriSurfacePointSourceFile &&
other.aprioriRadiusSource == aprioriRadiusSource &&
other.aprioriRadiusSourceFile == aprioriRadiusSourceFile &&
other.aprioriSurfacePoint == aprioriSurfacePoint &&
other.adjustedSurfacePoint == adjustedSurfacePoint &&
other.invalid == invalid &&
other.measures == measures &&
other.dateTime == dateTime &&
other.jigsawRejected == jigsawRejected &&
other.constraintStatus == constraintStatus &&
other.referenceExplicitlySet == referenceExplicitlySet &&
other.numberOfRejectedMeasures == numberOfRejectedMeasures &&
other.cubeSerials == cubeSerials &&
other.referenceMeasure == referenceMeasure;
}
/**
*
* @param pPoint
*
* @return ControlPoint&
*
* @internal
* @history 2011-09-13 Eric Hyer,Tracie Sucharski - Changed input parameter
* to const &. Re-wrote using Delete and AddMeasure
* methods, so that the ControlGraphNode is updated
* correctly.
* @history 2011-09-30 Tracie Sucharski - Fixed some memory leaks and
* deleted some calls that were already handled in
* AddMeasure.
* @history 2011-10-03 Tracie Sucharski - Unlock measures before Deleting
*/
const ControlPoint &ControlPoint::operator=(const ControlPoint &other) {
if (this != &other) {
bool oldLock = editLock;
editLock = false;
for (int i = cubeSerials->size() - 1; i >= 0; i--) {
(*measures)[cubeSerials->at(i)]->SetEditLock(false);
Delete(cubeSerials->at(i));
}
//measures->clear(); = new QHash< QString, ControlMeasure * >;
QHashIterator< QString, ControlMeasure * > i(*other.measures);
while (i.hasNext()) {
i.next();
ControlMeasure *newMeasure = new ControlMeasure;
*newMeasure = *i.value();
AddMeasure(newMeasure);
if (other.referenceMeasure == i.value()) {
SetRefMeasure(newMeasure);
}
}
invalid = other.invalid;
referenceExplicitlySet = other.referenceExplicitlySet;
numberOfRejectedMeasures = other.numberOfRejectedMeasures;
constraintStatus = other.constraintStatus;
SetId(other.id);
SetChooserName(other.chooserName);
SetDateTime(other.dateTime);
SetType(other.type);
SetRejected(other.jigsawRejected);
SetIgnored(other.ignore);
SetAprioriSurfacePointSource(other.aprioriSurfacePointSource);
SetAprioriSurfacePointSourceFile(other.aprioriSurfacePointSourceFile);
SetAprioriRadiusSource(other.aprioriRadiusSource);
SetAprioriRadiusSourceFile(other.aprioriRadiusSourceFile);
SetAprioriSurfacePoint(other.aprioriSurfacePoint);
SetAdjustedSurfacePoint(other.adjustedSurfacePoint);
// Set edit lock last so the it doesn't interfere with copying the other fields over.
editLock = oldLock;
SetEditLock(other.editLock);
}
return *this;
}
void ControlPoint::PointModified() {
dateTime = "";
}
//! Initialize the number of rejected measures to 0
void ControlPoint::ZeroNumberOfRejectedMeasures()
{
numberOfRejectedMeasures = 0;
}
/**
* Set (update) the number of rejected measures for the control point
*
* @param numRejected The number of rejected measures
*
*/
void ControlPoint::SetNumberOfRejectedMeasures(int numRejected) {
numberOfRejectedMeasures = numRejected;
}
/**
* Get the number of rejected measures on the control point
*
* @return The number of rejected measures on this control point
*
*/
int ControlPoint::GetNumberOfRejectedMeasures() const {
return numberOfRejectedMeasures;
}
/**
* Get rms of sample residuals
*
* @return The rms of sample residuals
*
*/
double ControlPoint::GetSampleResidualRms() const {
int nmeasures = measures->size();
if ( nmeasures <= 0 ) {
return 0.0;
}
Statistics stats;
for( int i = 0; i < nmeasures; i++) {
const ControlMeasure* m = GetMeasure(i);
if ( !m ) {
continue;
}
if ( !m->IsIgnored() || m->IsRejected() ) {
continue;
}
stats.AddData(m->GetSampleResidual());
}
return stats.Rms();
}
/**
* Get rms of line residuals
*
* @return The rms of line residuals
*
*/
double ControlPoint::GetLineResidualRms() const {
int nmeasures = measures->size();
if ( nmeasures <= 0 ) {
return 0.0;
}
Statistics stats;
for( int i = 0; i < nmeasures; i++) {
const ControlMeasure* m = GetMeasure(i);
if ( !m ) {
continue;
}
if ( !m->IsIgnored() || m->IsRejected() ) {
continue;
}
stats.AddData(m->GetLineResidual());
}
return stats.Rms();
}
/**
* Get rms of residuals
*
* @return The rms of residuals
*
*/
double ControlPoint::GetResidualRms() const {
int nmeasures = measures->size();
if ( nmeasures <= 0 ) {
return 0.0;
}
Statistics stats;
for( int i = 0; i < nmeasures; i++) {
const ControlMeasure* m = GetMeasure(i);
if ( !m ) {
continue;
}
if ( m->IsIgnored() || m->IsRejected() ) {
continue;
}
stats.AddData(m->GetSampleResidual());
stats.AddData(m->GetLineResidual());
}
return stats.Rms();
}
/**
* Set jigsaw rejected flag for all measures to false
* and set the jigsaw rejected flag for the point itself to false
*
*/
void ControlPoint::ClearJigsawRejected() {
int nmeasures = measures->size();
if ( nmeasures <= 0 ) {
return;
}
for( int i = 0; i < nmeasures; i++) {
ControlMeasure* m = GetMeasure(i);
if ( !m ) {
continue;
}
m->SetRejected(false);
}
SetRejected(false);
}
}