Skip to content
Snippets Groups Projects
Select Git revision
  • 254774043e81a96793aee16c145c094a823c0b43
  • master default protected
  • parallel_trapping
  • offload_trapping
  • script_devel
  • unify_iterations
  • containers-m10
  • magma_refinement
  • release9
  • enable_svd
  • parallel_angles_gmu
  • containers-m8
  • parallel_angles
  • profile_omp_leonardo
  • test_nvidia_profiler
  • containers
  • shaditest
  • test1
  • main
  • 3-error-in-run-the-program
  • experiment
  • NP_TMcode-M10a.03
  • NP_TMcode-M10a.02
  • NP_TMcode-M10a.01
  • NP_TMcode-M10a.00
  • NP_TMcode-M9.01
  • NP_TMcode-M9.00
  • NP_TMcode-M8.03
  • NP_TMcode-M8.02
  • NP_TMcode-M8.01
  • NP_TMcode-M8.00
  • NP_TMcode-M7.00
  • v0.0
33 results

oneAPI.sources

Blame
  • 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);
      }
    
    }