Commit 66607778 authored by Kristin Berry's avatar Kristin Berry
Browse files

Update ControlNet for review comments and some cleanup

parent d7217dd9
Loading
Loading
Loading
Loading
+92 −102
Original line number Diff line number Diff line
@@ -6,12 +6,10 @@
#include <cmath>
#include <sstream>

#include <QtAlgorithms>
#include <QDebug>
#include <QMutex>
#include <QMutexLocker>
#include <QPair>
#include <QQueue>
#include <QScopedPointer>
#include <QSet>
#include <QTime>
@@ -25,7 +23,6 @@
#include "ControlMeasure.h"
#include "ControlNetVersioner.h"
#include "ControlPoint.h"
#include "ControlCubeGraphNode.h"
#include "Distance.h"
#include "FileName.h"
#include "IException.h"
@@ -336,15 +333,15 @@ namespace Isis {
 /**
   * Adds a whole point to the control net graph. 
   *    
   * @throws IException::Programmer "NULL measure passed to ControlNet::AddControlCubeGraphNode!"
   * @throws IException::Programmer "NULL measure passed to ControlNet::pointAdded!"
   * @throws IException::Programmer "Control measure with NULL parent passed to
   *     ControlNet::AddControlCubeGraphNode!"
   *     ControlNet::pointAdded!"
   * @throws IException::Programmer "ControlNet does not contain the point."
   */
  void ControlNet::pointAdded(ControlPoint *point) {
    if (!point) {
      IString msg = "NULL point passed to "
          "ControlNet::AddControlCubeGraphNode!";
          "ControlNet::pointAdded!";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

@@ -354,25 +351,25 @@ namespace Isis {
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    // make sure there is a node for every measure
    // Make sure there is a node for every measure
    for (int i = 0; i < point->GetNumMeasures(); i++) {
      QString sn = point->GetMeasure(i)->GetCubeSerialNumber();

      // if the graph doesn't have the sn
      // If the graph doesn't have the sn, add a node for it
      if (!m_vertexMap.contains(sn)) {
        ImageVertex newVertex = boost::add_vertex(m_controlGraph); 
        m_controlGraph[newVertex].serial = sn; 
        Image newImage;
        newImage.serial = sn; 
        ImageVertex newVertex = boost::add_vertex(newImage, m_controlGraph); 
        m_vertexMap.insert(sn, newVertex);
      }
    }

    foreach(ControlMeasure* measure, point->getMeasures()) {
      // add the measure to the corresponding node
      // Add the measure to the corresponding node
      QString serial = measure->GetCubeSerialNumber();

      m_controlGraph[m_vertexMap[serial]].measures[measure->Parent()] = measure; 

      // in this measure's node add connections to the other nodes reachable from
      // In this measure's node add connections to the other nodes reachable from
      // its point
      if (!point->IsIgnored() && !measure->IsIgnored()) {
        for (int i = 0; i < point->GetNumMeasures(); i++) {
@@ -380,6 +377,9 @@ namespace Isis {
          if (!cm->IsIgnored()) {
            QString sn = cm->GetCubeSerialNumber();

            // If the edge doesn't already exist, this adds and returns the edge. 
            // If the edge already exists, this just returns it. (The use of a set
            // forces the edges to be unique.)
            ImageConnection connection = boost::add_edge(m_vertexMap[serial],
                                                         m_vertexMap[sn],
                                                         m_controlGraph).first;
@@ -390,8 +390,12 @@ namespace Isis {
    }
  }

// temporarily print graph to test
// This doesn't even return a string right now, just couts. 

  /**
   * Used for verifying graph intergrity
   *
   * @returns A string representation of the ControlNet graph
   */
  QString ControlNet::GraphToString() const {
    // Iterate through the vertices and print them out
    
@@ -420,29 +424,29 @@ namespace Isis {


   /**
   * Updates the ControlCubeGraphNode for the measure's serial number to
   * reflect the addition.  If there is currently no ControlCubeGraphNode for
   * this measure's serial, then a new ControlCubeGraphNode is created with
   * Updates the ControlNet graph for the measure's serial number to
   * reflect the addition.  If there is currently no node for
   * this measure's serial, then a new node is created with
   * this measure as its first.
   *
   * @param measure The measure added to the network.
   *
   * @throws IException::Programmer "NULL measure passed to ControlNet::AddControlCubeGraphNode!"
   * @throws IException::Programmer "NULL measure passed to ControlNet::measureAdded!"
   * @throws IException::Programmer "Control measure with NULL parent passed to
   *     ControlNet::AddControlCubeGraphNode!"
   *     ControlNet::measureAdded!"
   * @throws IException::Programmer "ControlNet does not contain the point."
   */
  void ControlNet::measureAdded(ControlMeasure *measure) {
    if (!measure) {
      IString msg = "NULL measure passed to "
          "ControlNet::AddControlCubeGraphNode!";
          "ControlNet::measureAdded!";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    ControlPoint *point = measure->Parent();
    if (!point) {
      IString msg = "Control measure with NULL parent passed to "
          "ControlNet::AddControlCubeGraphNode!";
          "ControlNet::measureAdded!";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

@@ -452,21 +456,21 @@ namespace Isis {
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    // make sure there is a node for every measure in this measure's parent
    // Make sure there is a node for every measure in this measure's parent
    for (int i = 0; i < point->GetNumMeasures(); i++) {
      QString sn = point->GetMeasure(i)->GetCubeSerialNumber();

      // if the graph doesn't have the sn (boost) 
      // If the graph doesn't have the sn, add the node.
      if (!m_vertexMap.contains(sn)) {
        ImageVertex newVertex = boost::add_vertex(m_controlGraph); 
        m_controlGraph[newVertex].serial = sn; 
        Image newImage;
        newImage.serial = sn; 
        ImageVertex newVertex = boost::add_vertex(newImage, m_controlGraph); 
        m_vertexMap.insert(sn, newVertex);
      }
    }

    // add the measure to the corresponding node
    // Add the measure to the corresponding node
    QString serial = measure->GetCubeSerialNumber();

    m_controlGraph[m_vertexMap[serial]].measures[measure->Parent()] = measure; 

    // in this measure's node add connections to the other nodes reachable from
@@ -477,6 +481,9 @@ namespace Isis {
        if (!cm->IsIgnored()) {
          QString sn = cm->GetCubeSerialNumber();

          // If the edge doesn't already exist, this adds and returns the edge. 
          // If the edge already exists, this just returns it. (The use of a set
          // forces the edges to be unique.)
          ImageConnection connection = boost::add_edge(m_vertexMap[serial],
                                                         m_vertexMap[sn],
                                                         m_controlGraph).first;
@@ -488,28 +495,28 @@ namespace Isis {


  /**
   * Updates the connections for the ControlCubeGraphNode associated with the
   * Updates the connections for the ControlNet graph associated with the
   * measure's serial number to reflect the unignoration.
   *
   * @param measure The measure unignored from the network.
   *
   * @throws IException::Programmer "NULL measure passed to ControlNet::AddControlCubeGraphNode!"
   * @throws IException::Programmer "NULL measure passed to ControlNet::measureUnIgnored!"
   * @throws IException::Programmer "Control measure with NULL parent passed to
   *     ControlNet::AddControlCubeGraphNode!"
   *     ControlNet::measureUnIgnored!"
   * @throws IException::Programmer "ControlNet does not contain the point."
   * @throws IException::Programmer "Node does not exist for the cube serial number."
   */
  void ControlNet::measureUnIgnored(ControlMeasure *measure) {
    if (!measure) {
      IString msg = "NULL measure passed to "
          "ControlNet::AddControlCubeGraphNode!";
          "ControlNet::measureUnIgnored!";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    ControlPoint *point = measure->Parent();
    if (!point) {
      IString msg = "Control measure with NULL parent passed to "
          "ControlNet::AddControlCubeGraphNode!";
          "ControlNet::measureUnIgnored!";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

@@ -519,7 +526,7 @@ namespace Isis {
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    // make sure there is a node for every measure in this measure's parent
    // Make sure there is a node for every measure in this measure's parent
    for (int i = 0; i < point->GetNumMeasures(); i++) {
      QString sn = point->GetMeasure(i)->GetCubeSerialNumber();
      if (!m_vertexMap.contains(sn)) {
@@ -532,13 +539,16 @@ namespace Isis {
    if (!point->IsIgnored()) {
      QString serial = measure->GetCubeSerialNumber();

      // in this measure's node add connections to the other nodes reachable
      // In this measure's node add connections to the other nodes reachable
      // from its point
      for (int i = 0; i < point->GetNumMeasures(); i++) {
        ControlMeasure *cm = point->GetMeasure(i);
        if (!cm->IsIgnored()) {
          QString sn = cm->GetCubeSerialNumber();

          // If the edge doesn't already exist, this adds and returns the edge. 
          // If the edge already exists, this just returns it. (The use of a set
          // forces the edges to be unique.)
          ImageConnection connection = boost::add_edge(m_vertexMap[serial],
                                                       m_vertexMap[sn],
                                                       m_controlGraph).first;
@@ -565,9 +575,9 @@ namespace Isis {


  /**
   * Updates the ControlCubeGraphNode for this measure's serial number to
   * Updates the node for this measure's serial number to
   * reflect the deletion.  If this is the only measure left in the containing
   * ControlCubeGraphNode, then the ControlCubeGraphNode is deleted as well.
   * node, then the node is deleted as well.
   *
   * @param measure The measure removed from the network.
   */
@@ -576,16 +586,18 @@ namespace Isis {
    QString serial = measure->GetCubeSerialNumber();
    ASSERT(m_vertexGraph->contains(serial));

    // remove connections to and from this node
    // Remove connections to and from this node
    if (!measure->IsIgnored() && !measure->Parent()->IsIgnored()) {
      // Break connections
      measureIgnored(measure);
    }
    
    // Remove the measure from the associated node.  
    // Conceptually, I think this belongs in measureIgnored, but it isn't done
    // for the old graph. 
    m_controlGraph[m_vertexMap[serial]].measures.remove(measure->Parent()); 

    // Decrement the edge strength & remove edge if -> 0 happens in measureIgnored

    // If this caused the node to be empty, then delete the node.
    if (m_controlGraph[m_vertexMap[serial]].measures.size() <= 0) {
      boost::clear_vertex(m_vertexMap[serial], m_controlGraph);
@@ -595,36 +607,46 @@ namespace Isis {
  }


  /**
   * Updates the edges in the ControlNet graph to reflect the ignored 
   * measure. If this was the last measure connecting one node to another, 
   * then the edge is deleted as well.
   *
   * @param measure The measure set to ignored from the network.
   */
  void ControlNet::measureIgnored(ControlMeasure *measure) {
    if (!measure) {
      IString msg = "NULL measure passed to "
          "ControlNet::AddControlCubeGraphNode!";
          "ControlNet::measureIgnored!";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    ControlPoint *point = measure->Parent();
    if (!point) {
      IString msg = "Control measure with NULL parent passed to "
          "ControlNet::AddControlCubeGraphNode!";
          "ControlNet::measureIgnored!";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    QString serial = measure->GetCubeSerialNumber();
    if (!m_vertexMap.contains(serial)) {
    if (!ValidateSerialNumber(serial)) {
      QString msg = "Node does not exist for [";
      msg += serial + "]";
      throw IException(IException::Programmer, msg, _FILEINFO_);
    }

    // remove connections to and from this node
    // Decrement the edge strength for edges from this node 
    // Remove edge if the strength becomes 0. 
    for (int i = 0; i < point->GetNumMeasures(); i++) {
      QString sn = point->GetMeasure(i)->GetCubeSerialNumber();
      if (m_vertexMap.contains(sn)) {
        if (QString::compare(serial, sn) !=0) {
//          std::cout << point->GetId() << ":" << serial << " --- " << sn << std::endl; 

          // This is necessary because boost doesn't add separate edges for A -> B and
          // B -> A like we used to. 
          // We need to check if the edge still exists. 
          // boost doesn't add separate edges for A -> B and B -> A like the old graph. 
          // result.first is the ImageConnection, if found
          // result.second is true if the edge exists; otherwise false. 
          std::pair<ImageConnection, bool> result = boost::edge(m_vertexMap[serial],
                                                                m_vertexMap[sn],
                                                                m_controlGraph);
@@ -746,6 +768,7 @@ namespace Isis {
    VertexIndexMap indexMap;
    VertexIndexMapAdaptor indexMapAdaptor(indexMap);

    // Needed to use connected_componenets
    QList< QString> serials = m_vertexMap.keys(); 
    for (int i = 0; i < serials.size(); i++) {
      boost::put(indexMapAdaptor, m_vertexMap[serials[i]], i);
@@ -753,42 +776,25 @@ namespace Isis {

    VertexIndexMap componentMap;
    VertexIndexMapAdaptor componentAdaptor(componentMap);
    size_t numComponents = boost::connected_components(m_controlGraph, componentAdaptor,
    boost::connected_components(m_controlGraph, componentAdaptor,
                                                      boost::vertex_index_map(indexMapAdaptor));

//    std::cout << "Number of components:" << std::endl;
//    std::cout << numComponents << std::endl; 
//    std::cout << "Size of return: " << componentMap.size() << std::endl; 

    // This is not efficient, but works
    QHash<int, QList<QString> > islandsByGroup; 

    std::map<ImageVertex, size_t>::iterator it = componentMap.begin();
    while(it != componentMap.end())
    {
      ImageVertex vertex = it->first;
      QString serial = m_controlGraph[vertex].serial;
      
      QString serial = m_controlGraph[it->first].serial;
      int group = (int) it->second;
      
 //     std::cout << group << "  ::  "  << serial << std::endl; 
      islandsByGroup[group].append(serial); 
      
      ++it;
      if (group > islandStrings.size() - 1) {
        QList<QString> tempList; 
        tempList.append(serial);
        islandStrings.append(tempList); 
      }

//   std::cout << std::endl; 

    QList<int> groups = islandsByGroup.keys();
    for (int i=0; i<groups.size(); i++) {
      std::cout << "Group: " << groups[i] << std::endl; 
      QList<QString> temp = islandsByGroup[groups[i]];
      islandStrings.append(temp); // <--- this converts to the output format;
      for (int j=0; j<temp.size();j++) {
        std::cout << " ----- " << temp[j] << std::endl; 
      else {
        islandStrings[group].append(serial); 
      }
      ++it;
    }

    return islandStrings;
  }

@@ -797,9 +803,7 @@ namespace Isis {
   * @returns The total number of edges in the bi-directional graph for images
   */
  int ControlNet::getEdgeCount() const {
    int total = boost::num_edges(m_controlGraph); 

    return total;
    return boost::num_edges(m_controlGraph); 
  }


@@ -823,11 +827,7 @@ namespace Isis {
   * @param serialNumber the cube serial number to validate
   */
  bool ControlNet::ValidateSerialNumber(QString serialNumber) const {

    if (!m_vertexMap.contains(serialNumber)) {
      return false;
    }
    return true; 
    return m_vertexMap.contains(serialNumber);
  }


@@ -837,14 +837,13 @@ namespace Isis {
   * @returns A list of all measures which are in a given cube
   */
  QList< ControlMeasure * > ControlNet::GetMeasuresInCube(QString serialNumber) {
    if( ValidateSerialNumber(serialNumber) ) {
      return m_controlGraph[m_vertexMap[serialNumber]].measures.values();
    }
    else {
    if( !ValidateSerialNumber(serialNumber) ) {
      IString msg = "Cube Serial Number [" + serialNumber + "] not found in "
          "the network";
      throw IException(IException::Programmer, msg, _FILEINFO_);
      
    }
    return m_controlGraph[m_vertexMap[serialNumber]].measures.values();
  }


@@ -917,7 +916,7 @@ namespace Isis {
      ControlPoint *point = this->GetPoint(i);
      if (point->IsIgnored()) continue;  //if the point is ignored then continue

        //get the number of measures
      // Get the number of measures
      int nObs = point->GetNumMeasures();
      for (int j=0;j<nObs;j++) {  //for every measure
        ControlMeasure *measure = point->GetMeasure(j);
@@ -928,7 +927,7 @@ namespace Isis {
      }
    }

    //sort the measures
    // Sort the measures
    ControlMeasureLessThanFunctor lessThan(statFunc);
    qSort(measures.begin(),measures.end(),lessThan);

@@ -1045,12 +1044,6 @@ namespace Isis {
   */
  ControlPoint *ControlNet::FindClosest(QString serialNumber,
      double sample, double line) {
//  if (!cubeGraphNodes->contains(serialNumber)) {
//    QString msg = "serialNumber [";
//    msg += serialNumber;
//    msg += "] not found in ControlNet";
//    throw IException(IException::Programmer, msg, _FILEINFO_);
//  }

    if (!ValidateSerialNumber(serialNumber)) {
      QString msg = "serialNumber [";
@@ -1063,9 +1056,6 @@ namespace Isis {
    double minDist = SEARCH_DISTANCE;
    ControlPoint *closestPoint = NULL;

//    ControlCubeGraphNode *csn = (*cubeGraphNodes)[serialNumber];
//    QList< ControlMeasure * > measures = csn->getMeasures();

    QList < ControlMeasure * > measures = m_controlGraph[m_vertexMap[serialNumber]].measures.values();

    for (int i = 0; i < measures.size(); i++) {
+2 −4
Original line number Diff line number Diff line
@@ -36,7 +36,6 @@
#include <boost/graph/adjacency_list.hpp>
#include <boost/graph/connected_components.hpp>


template< typename A, typename B > class QHash;
template< typename T > class QList;
template< typename A, typename B > struct QPair;
@@ -45,7 +44,6 @@ template< typename T > class QSet;
class QMutex;
class QString;


namespace Isis {
  class Camera;
  class ControlMeasure;
@@ -369,6 +367,8 @@ namespace Isis {
      //! hash ControlPoints by ControlPoint Id
      QHash< QString, ControlPoint * > * points;

      //! hash ControlCubeGraphNodes by CubeSerialNumber

      // structs and typedefs for the boost graph
      struct Image {
        QString serial;
@@ -385,10 +385,8 @@ namespace Isis {
      typedef std::map<ImageVertex, size_t> VertexIndexMap;
      typedef boost::associative_property_map<VertexIndexMap> VertexIndexMapAdaptor;
      typedef Network::out_edge_iterator ConnectionIterator;

      QHash<QString, ImageVertex> m_vertexMap; //!< The SN -> vertex hash for the boost graph
      Network m_controlGraph; //!< The boost graph

      QStringList *pointIds;
      QMutex *m_mutex;