make the path view independent of type of connection
authorDiane Trout <diane@caltech.edu>
Wed, 15 Mar 2006 09:45:59 +0000 (09:45 +0000)
committerDiane Trout <diane@caltech.edu>
Wed, 15 Mar 2006 09:45:59 +0000 (09:45 +0000)
I moved the opengl code for drawing multiple tracks with paths
connecting various elements into GlTracks. This also includes the performance
improvement of only drawing a track once.

Unfortunately I disabled the selection code, as I'm not sure how much
should live at the Qt level and how much should live at the opengl level.

Even more difficult is the problem that a segment can belong to _many_
paths. Which makes my old each path having one pathid not so likely to work--
especially since there's a limit to how many names one can have.

Unfortunately for a large dataset, there's a segfault on closing.

16 files changed:
alg/glsequence.cpp
alg/glsequence.hpp
alg/gltracks.cpp [new file with mode: 0644]
alg/gltracks.hpp [new file with mode: 0644]
alg/module.mk
alg/sequence.cpp
alg/sequence.hpp
alg/test/module.mk
alg/test/test_color.cpp
mussagl.pro
qui/PathScene.cpp
qui/PathScene.hpp
qui/PathWidget.cpp
qui/PathWidget.hpp
qui/PathWindow.cpp
qui/PathWindow.hpp

index 674dcb0ea819a319d9b95d3c734e258f0cbf0f04..d802d6284f0878d5e63f4ffd83eb86947e82ad74 100644 (file)
@@ -70,6 +70,11 @@ GLfloat GlSequence::y() const
   return seq_y;
 }
 
+GLfloat GlSequence::height() const
+{
+  return seq_height;
+}
+
 GLfloat GlSequence::length() const
 {
   return seq.size();
@@ -194,6 +199,7 @@ void GlSequence::draw_box(GLfloat left, GLfloat right,
     glVertex3f(right, top,    z);
   glEnd();
 }
+
 void GlSequence::draw_track(GLfloat left, GLfloat right) const
 {
   glColor3fv(drawColor.get());
@@ -228,7 +234,6 @@ void GlSequence::draw_annotations(GLfloat left, GLfloat right) const
 
 }
 
-
 const int PT = 1;
 const int STROKE = 2;
 const int END =3;
index c8c9b2b7eb58c41f1fe819c0f2670ffa32aabcb3..3916687cee56c0272c3476b4c4a12681642322b3 100644 (file)
@@ -30,6 +30,8 @@ public:
   void setY(GLfloat);
   //! get our current y (vertical) position
   GLfloat y() const;
+  //! how thick (high) the track we're drawing is
+  GLfloat height() const;
   //! how long is our sequence track? (computed from the sequence)
   GLfloat length() const;
  
diff --git a/alg/gltracks.cpp b/alg/gltracks.cpp
new file mode 100644 (file)
index 0000000..7f11c5b
--- /dev/null
@@ -0,0 +1,327 @@
+#include "alg/gltracks.hpp"
+
+#include <iostream>
+#include <stdexcept>
+
+using namespace std;
+
+GlTracks::GlTracks()
+  : border(25),
+    max_ortho(400.0, 0.0, 600.0, 0.0),
+    cur_ortho(max_ortho),
+    viewport_size(600, 400),
+    viewport_center(0),
+    zoom_level(2),
+    color_mapper(),
+    track_container()
+{
+}
+
+GlTracks::GlTracks(const GlTracks& gt)
+  : border(gt.border),
+    max_ortho(gt.max_ortho),
+    cur_ortho(gt.cur_ortho),
+    viewport_size(gt.viewport_size),
+    viewport_center(gt.viewport_center),
+    zoom_level(gt.zoom_level),
+    color_mapper(gt.color_mapper),
+    track_container(gt.track_container)
+{
+}
+
+void GlTracks::initializeGL()
+{
+  glEnable(GL_DEPTH_TEST);
+  glClearColor(1.0, 1.0, 1.0, 0.0);
+  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
+  glShadeModel(GL_FLAT);
+}
+
+void GlTracks::resizeGL(int width, int height)
+{
+  viewport_size.x = width;
+  viewport_size.y = height;
+  glViewport(0, 0, (GLsizei)width, (GLsizei)height);
+  //update_layout();
+}
+
+void GlTracks::paintGL() const
+{
+  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
+
+  glPushMatrix();
+  glMatrixMode(GL_PROJECTION);
+  glLoadIdentity();
+  glOrtho(cur_ortho.left, cur_ortho.right,
+          cur_ortho.bottom, cur_ortho.top,
+          -50.0, 50);
+
+  draw();
+
+  glPopMatrix();
+  glFlush();
+}
+
+float GlTracks::left() const
+{ 
+  return max_ortho.left; 
+}
+
+float GlTracks::right() const
+{ 
+  return max_ortho.right; 
+}
+
+void GlTracks::setViewportCenter(float x)
+{
+  update_viewport(x, zoom_level);
+  viewport_center = x;
+}
+
+float GlTracks::viewportLeft() const
+{ 
+  return cur_ortho.left; 
+}
+
+float GlTracks::viewportCenter() const
+{
+  return viewport_center;
+}
+
+float GlTracks::viewportRight() const
+{ 
+  return cur_ortho.right; 
+}
+
+float GlTracks::viewportHeight() const
+{
+  return cur_ortho.top - cur_ortho.bottom;
+}
+
+float GlTracks::viewportWidth() const
+{
+  return cur_ortho.right - cur_ortho.left;
+}
+
+void GlTracks::setZoom(int new_zoom)
+{
+  update_viewport(viewport_center, new_zoom);
+  zoom_level = new_zoom;
+}
+
+int GlTracks::zoom() const
+{
+  return zoom_level;
+}
+
+void GlTracks::setColorMapper(AnnotationColors& cm)
+{
+  color_mapper = cm;
+}
+
+AnnotationColors& GlTracks::colorMapper()
+{
+  return color_mapper;
+}
+
+void GlTracks::clear()
+{
+  //clear_links();
+  //path_segments.clear();
+  track_container.clear();
+}
+
+void GlTracks::push_sequence(const Sequence &s)
+{
+  GlSequence gs(s, color_mapper);
+  push_sequence(gs);
+}
+
+void GlTracks::push_sequence(GlSequence &gs)
+{
+  //clear_links();
+  pathid = 0;
+  track_container.push_back(gs);
+  update_layout();
+  if (track_container.size() > 1)
+    path_segments.push_back(pair_segment_map());
+}
+
+const std::vector<GlSequence>& GlTracks::tracks() const
+{
+  return track_container;
+}
+
+void GlTracks::clear_links()
+{
+  path_segment_map_vector::iterator psmv_i;
+  for(psmv_i = path_segments.begin();
+      psmv_i != path_segments.end();
+      ++psmv_i)
+  {
+    psmv_i->clear();
+  }
+}
+
+void 
+GlTracks::link(vector<int> path, vector<bool> rc, int length)
+{
+  if (path.size() < 2) {
+    // should i throw an error instead?
+    return;
+  }
+  if (path.size() != rc.size()) {
+    throw runtime_error("path and reverse compliment must be the same length");
+  }
+  vector<int>::iterator path_i = path.begin();
+  vector<bool>::iterator rc_i = rc.begin();
+  int track_i = 0;
+  int prev_x = *path_i; ++path_i;
+  bool prev_rc = *rc_i; ++rc_i;
+  while (path_i != path.end() and rc_i != rc.end())
+  {
+    segment_key p(prev_x, *path_i);
+    pair_segment_map::iterator found_segment = path_segments[track_i].find(p);
+    if (found_segment == path_segments[track_i].end()) {
+      // not already found
+      float y1 = track_container[track_i].y();
+            y1 -= track_container[track_i].height()/2;
+      float y2 = track_container[track_i+1].y();
+            y2 -= track_container[track_i+1].height()/2;
+            
+      Segment s(prev_x, y1, *path_i, y2, prev_rc);
+      s.path_ids.push_back(pathid);
+      path_segments[track_i][p] = s;
+    } else {
+      //found
+      found_segment->second.path_ids.push_back(pathid);
+    }
+    prev_x = *path_i;
+    prev_rc = *rc_i;
+    ++track_i;
+    ++path_i;
+    ++rc_i;
+  }
+  // pathid is reset by push_sequence
+  ++pathid;
+}
+
+void GlTracks::update_viewport(float center, int new_zoom)
+{
+  float max_width = max_ortho.width();
+  // division by zero is a major bummer
+  if (new_zoom < 1) {
+    new_zoom = 1;
+  }
+  float new_max_width = max_width / new_zoom;
+  cur_ortho.left = center-new_max_width;
+  cur_ortho.right = center+new_max_width;
+}
+
+void GlTracks::update_layout()
+{
+  typedef std::vector<GlSequence>::iterator glseq_itor_type;
+  float available_height = (float)cur_ortho.top - 2 * (float)border;
+  float max_base_pairs = 0;
+  size_t track_count = track_container.size();
+
+  if (track_count > 1) {
+    // we have several tracks
+    float track_spacing = available_height / (track_count-1);
+    float y = available_height + (float)border;
+    for(glseq_itor_type seq_i = track_container.begin();
+        seq_i != track_container.end();
+        ++seq_i, y-=track_spacing)
+    {
+      seq_i->setX(0);
+      seq_i->setY(y);
+      if (seq_i->length() > max_base_pairs)
+        max_base_pairs = seq_i->length();
+    }
+  } else if (track_count == 1) {
+    // center the single track
+    glseq_itor_type seq_i = track_container.begin();
+    seq_i->setX(0);
+    seq_i->setY(viewport_size.x /2);
+    max_base_pairs = seq_i->length();
+  } else {
+    // nothing to do as we're empty
+    return;
+  }
+  max_ortho.right = max_base_pairs + border;
+  max_ortho.left = -border;
+  max_ortho.top = viewport_size.x;
+  max_ortho.bottom = 0;
+  cur_ortho = max_ortho;
+  viewport_center = (cur_ortho.width()/2) + cur_ortho.left;
+}
+
+void GlTracks::draw() const
+{
+  glMatrixMode(GL_MODELVIEW);
+  //glInitNames();
+  //glPushName(MussaPaths);
+  draw_segments();
+  draw_tracks();
+  draw_selection();
+  //glPopName();
+}
+
+void GlTracks::draw_selection() const
+{
+  /* draw selection box
+  glEnable(GL_BLEND);
+  glDepthMask(GL_FALSE);
+  if (selectedMode && !drawingBand) {
+    glColor4f(0.6, 0.6, 0.6, 0.9);
+    glRectf(previousBand.x(), previousBand.y(),
+            previousBand.right(), previousBand.bottom());
+  }
+  glDepthMask(GL_TRUE);
+  glDisable(GL_BLEND);
+  */
+}
+
+void GlTracks::draw_tracks() const
+{
+  typedef std::vector<GlSequence>::const_iterator glseq_citor_type;
+  for(glseq_citor_type seq_i = track_container.begin();
+      seq_i != track_container.end();
+      ++seq_i)
+  {
+    seq_i->draw(cur_ortho.left, cur_ortho.right);
+  }
+}
+
+void GlTracks::draw_segments() const
+{
+  glLineWidth(0.1);
+  glBegin(GL_LINES);
+  // each vector contains path_segment_maps of all the connections
+  // between this track and the next
+  path_segment_map_vector::const_iterator psmv_i;
+  for(psmv_i = path_segments.begin();
+      psmv_i != path_segments.end();
+      ++psmv_i)
+  {
+    // these maps contain the pair index (used so we dont keep drawing the
+    // same segment) and the actual segment structure.
+    pair_segment_map::const_iterator psm_i;
+    for(psm_i = psmv_i->begin();
+        psm_i != psmv_i->end();
+        ++psm_i)
+    {
+      // the second element of our map pair is a segment
+      const Segment &s = psm_i->second;
+      // need to do something so we can detect our selection
+      if (not s.reversed) {
+        glColor3f(1.0, 0.0, 0.0);
+      } else { 
+        glColor3f(0.0, 0.0, 1.0);
+      }
+      glVertex3f(s.start.x, s.start.y, -1);
+      glVertex3f(s.end.x, s.end.y, -1);
+    }
+  }
+  glEnd();
+}
diff --git a/alg/gltracks.hpp b/alg/gltracks.hpp
new file mode 100644 (file)
index 0000000..6df83ef
--- /dev/null
@@ -0,0 +1,137 @@
+#ifndef _GLTRACKS_H_
+#define _GLTRACKS_H_
+
+#include <map>
+#include <vector>
+
+#include "alg/annotation_colors.hpp"
+#include "alg/sequence.hpp"
+#include "alg/glsequence.hpp"
+
+//! Manage rendering a collection of glSequences
+class GlTracks
+{
+public:
+  GlTracks();
+  GlTracks(const GlTracks&);
+
+  //! setup the opengl canvas
+  void initializeGL();
+  //! called when our screen canvas is resized
+  void resizeGL(int width, int height);
+  //! render our scene
+  void paintGL() const;
+
+  //! max world left coordinate
+  float left() const;
+  //! max world right coordinate
+  float right() const;
+
+  void setViewportCenter(float x);
+  float viewportLeft() const;
+  float viewportCenter() const;
+  float viewportRight() const;
+  float viewportHeight() const;
+  float viewportWidth() const;
+
+  void setZoom(int zoom_level);
+  int zoom() const;
+
+  void setColorMapper(AnnotationColors& cm);
+  AnnotationColors& colorMapper();
+
+  //! clear our tracks and connections
+  void clear();
+
+  //! add a sequence to the back of our track container
+  void push_sequence(const Sequence &s);
+  //! add a glsequence to the back of our track container
+  void push_sequence(GlSequence &s);
+  //! return our track container
+  const std::vector<GlSequence>& tracks() const;
+
+  //! clear all the line segments between all the sequences
+  void clear_links();
+  //! define a path
+  void link(std::vector<int> path, std::vector<bool> isRC, int length);
+
+  //! a useful point class
+  template<class T> struct point {
+    T x;
+    T y;
+
+    point(T x_, T y_):x(x_), y(y_) {}
+  };
+
+  //! a useful rectangle, where 0,0 is in the lower left
+  template<class T> struct rect {
+    T top;
+    T left;
+    T bottom;
+    T right;
+
+    rect(T t, T l, T b, T r) : top(t), left(l), bottom(b), right(r) {}
+    T width() { return right - left; }
+    T height() { return top - bottom; }
+  };
+
+  struct Segment
+  {
+    point<float> start;
+    point<float> end;
+    bool reversed;
+    std::list<int> path_ids;
+
+    Segment() : start(0.0, 0.0), end(0.0, 0.0) {}
+    Segment(float x1, float y1, float x2, float y2, bool isRC) 
+      : start(x1, y1), end(x2, y2), reversed(isRC) {}
+  };
+
+  //! data structure holding our line segments
+  /*! the vector is of size track_container.size()-1
+   *  it's indexed by the pair x1, x2 (the two x coordinates between
+   *  the two tracks
+   */
+  typedef std::pair<int, int> segment_key;
+  typedef std::map<segment_key, Segment> pair_segment_map;
+  typedef std::vector<pair_segment_map> path_segment_map_vector;
+  path_segment_map_vector path_segments;
+private:
+  //! recalculate the viewable world
+  /*! depending on the size of our canvas, our zoom level and
+   *  how far we've been offset
+   */
+  void update_viewport(float center, int new_zoom);
+
+  //! determine where all the tracks should be placed
+  void update_layout();
+
+  //! master scene drawing function
+  /*! draw is broken out for the opengl selection code
+   */
+  void draw() const;
+  //! draw glsequence tracks
+  void draw_tracks() const;
+  //! draw line segments between tracks
+  void draw_segments() const;
+  //! draw selection box
+  void draw_selection() const;
+
+  //! number of pixels to reserve around the edges of our canvas
+  const int border;
+  //! the maximum dimensions that our scene is taking up (world coord)
+  rect<float> max_ortho;
+  //! the current viewable region (world coord)
+  rect<float> cur_ortho;
+  //! how many pixels our viewport is (screen coord)
+  point<int> viewport_size;
+  //! the center of our current viewport (world coord) (used for scrollbar)
+  float viewport_center;
+  int zoom_level;
+  AnnotationColors color_mapper;
+  //! container of all the GlSequences loaded into our scene
+  std::vector<GlSequence> track_container;
+  //! counter for each path added to us via connect
+  int pathid;
+};
+#endif
index 0d157ce034aa29411a23fb6dd4f4f5cc759ef0ad..4a215ed36ba04ba198b71542e9312182a4468075 100644 (file)
@@ -15,7 +15,8 @@ SOURCES.cpp := annotation_colors.cpp \
 MUSSA_ALG_SRC := $(addprefix $(CURDIR), $(SOURCES.cpp))
 MUSSA_ALG_OBJ := $(MUSSA_ALG_SRC:.cpp=$(OBJEXT))
 
-GLSOURCES.cpp := glsequence.cpp 
+GLSOURCES.cpp := glsequence.cpp  \
+                 gltracks.cpp
 MUSSA_ALG_GL_SRC := $(addprefix $(CURDIR), $(GLSOURCES.cpp))
 MUSSA_ALG_GL_OBJ := $(MUSSA_ALG_GL_SRC:.cpp=$(OBJEXT))
 
index 4161bfcd7d1f33ba62a941111bd3e18b0c984378..26215a4d428f15e15657847013f7a3f8ffa0a2b0 100644 (file)
@@ -83,6 +83,12 @@ Sequence &Sequence::operator=(const std::string& s)
   return *this;
 }
 
+ostream& operator<<(ostream& out, const Sequence& seq)
+{
+  out << "Sequence(" << seq.get_seq() << ")";
+  return out;
+}
+
 //! load a fasta file into a sequence
 /*! 
  * \param file_path the location of the fasta file in the filesystem
index e4771f200c97960d44a5eaf89a89d4019c206601..eaf65e7dcf2133e89a05ba56cf79c873377f1853 100644 (file)
@@ -19,6 +19,7 @@
 #include <list>
 #include <string>
 #include <vector>
+#include <iostream>
 
 // Sequence data class
 
@@ -71,6 +72,7 @@ class Sequence
     //! assignment to constant sequences
     Sequence &operator=(const Sequence&);
     Sequence &operator=(const std::string &);
+    friend std::ostream& operator<<(std::ostream& out, const Sequence& seq);
 
     //! set sequence to a (sub)string containing nothing but AGCTN
     void set_filtered_sequence(const std::string& seq, 
index a23177fba56a02d7a66fa5899a7bf58403f12bef..81c8cce3239ba1dac33e63a381156978a0b1e56c 100644 (file)
@@ -4,6 +4,7 @@ SOURCES.cpp := test_annotation_color.cpp \
                test_conserved_path.cpp \
                test_flp.cpp \
                test_glsequence.cpp \
+               test_gltracks.cpp \
                                                         test_color.cpp \
                test_main.cpp \
                test_mussa.cpp \
index a3d4134a0c4dd5a87906adace01994d86358d01c..cdae872715f1c3bb3bc173028e4c628fda5fef48 100644 (file)
@@ -1,6 +1,7 @@
 #include <boost/test/auto_unit_test.hpp>
 #include <boost/test/floating_point_comparison.hpp>
 #include <string>
+#include <sstream>
 
 #include "alg/color.hpp"
 
@@ -39,5 +40,3 @@ BOOST_AUTO_TEST_CASE ( color )
   BOOST_CHECK_CLOSE (colors[Color::BlueChannel  ], dotthree, tolerance );
   BOOST_CHECK_CLOSE (colors[Color::AlphaChannel ], dotfour, tolerance );
 }
-
-
index 82b4fd768e7474d9cb582a34cd4b40f27bf1496b..639ee431e956f33e3dee436c20cc8031ee9d26c7 100644 (file)
@@ -23,6 +23,7 @@ HEADERS += mussa_exceptions.hpp \
            alg/conserved_path.hpp \
            alg/flp.hpp \
            alg/glsequence.hpp \
+           alg/gltracks.hpp \
            alg/mussa.hpp \
            alg/nway_paths.hpp \
            alg/parse_options.hpp \
@@ -40,6 +41,7 @@ SOURCES += mussagl.cpp \
            alg/flp.cpp \
            alg/flp_seqcomp.cpp \
            alg/glsequence.cpp \
+           alg/gltracks.cpp \
            alg/mussa.cpp \
            alg/nway_entropy.cpp \
            alg/nway_other.cpp \
index 7040b6969fd71667e284357122ed4cfffefbc95a..43195f6cd5bb8cb4435b0e4d046560d10f8b16b1 100644 (file)
 
 using namespace std;
 
-PathScene::PathScene(Mussa* analysis, QWidget *parent) : 
-  QGLWidget(parent),
-  viewport_height(0),
-  viewport_width(0),
-  clipZ(30.0),
-  zoom(2),
-  maxOrtho2d(-50.0, -50, 3000000.0, 300.0),
-  curOrtho2d(maxOrtho2d),
-  viewport_center(((curOrtho2d.right()-curOrtho2d.left())/2)+curOrtho2d.left()),
-  selectedMode(false),
-  rubberBand(0),
-  drawingBand(false)
+PathScene::PathScene(QWidget *parent)
+  : QGLWidget(parent)
+    //selectedMode(false),
+    //rubberBand(0),
+    //drawingBand(false)
 { 
-  if (analysis == 0)
-  {
-    mussaAnalysis = new Mussa;
-  }
-  else
-  {
-    mussaAnalysis = analysis;
-  }
-  updateScene();
 }
 
 QSize PathScene::sizeHint() const
 {
-  return QSize(400, 400);
-}
-
-float PathScene::left()
-{
-  return maxOrtho2d.left();
-}
-
-float PathScene::right()
-{
-  return maxOrtho2d.right();
-}
-
-float PathScene::viewportLeft()
-{
-  return curOrtho2d.left();
-}
-
-float PathScene::viewportRight()
-{
-  return curOrtho2d.right();
+  return QSize(GlTracks::viewportHeight(), GlTracks::viewportWidth());
 }
 
-float PathScene::viewportCenter()
+void PathScene::setViewportCenter(float x)
 {
-  return viewport_center;
-}
+  const float epsilon = 1e-10;
+  float center = fabs(GlTracks::viewportCenter());
+  float abs_x = fabsf(x);
+  float difference = fabsf(abs_x - center);
 
-void PathScene::updateViewport(float center, int new_zoom)
-{
-  float max_width = maxOrtho2d.width();
-  if (new_zoom < 1) new_zoom = 1;
-  float new_max_width = max_width / new_zoom;
-  //curOrtho2d.setLeft(max(center-new_max_width, maxOrtho2d.left()));
-  //curOrtho2d.setRight(min(center+new_max_width, maxOrtho2d.right()));
-  curOrtho2d.setLeft(center-new_max_width);
-  curOrtho2d.setRight(center+new_max_width);
-  emit viewportChanged();
-}
-
-void PathScene::setViewportX(float x)
-{
   //hopefully this calculates a sufficiently reasonable == for a float
-  if (x != viewport_center )
+  if (difference < epsilon * abs_x or difference < epsilon * center)
   {
-    updateViewport(x, zoom);
-    viewport_center = x;
+    GlTracks::setViewportCenter(x);
     update();
   }
 }
 
 void PathScene::setZoom(int new_zoom)
 {
-  if (zoom != new_zoom) {
-    // try to figure out where we should be now?
-    updateViewport(viewport_center, new_zoom);
-    zoom = new_zoom;
+  if (new_zoom != GlTracks::zoom()) {
+    GlTracks::setZoom(new_zoom);
     update();
   }
 }
 
-void PathScene::setClipPlane(int newZ)
+void PathScene::setClipPlane(int )
 {
+/*
   if (clipZ != (double) newZ){
     clipZ = (double) newZ;
     update();
   }
-}
-
-void PathScene::loadMotifList()
-{
-  QString caption("Load a motif list");
-  QString filter("Motif list(*.txt *.mtl)");
-  QString path = QFileDialog::getOpenFileName(this,
-                                                   caption, 
-                                                   QDir::currentPath(),
-                                                   filter);
-  // user hit cancel?
-  if (path.isNull()) 
-    return;
-  // try to load safely
-  try {
-    mussaAnalysis->load_motifs(path.toStdString());
-    updateScene();
-  } catch (runtime_error e) {
-    QString msg("Unable to load ");
-    msg += path;
-    msg += "\n";
-    msg += e.what();
-    QMessageBox::warning(this, "Load Motifs", msg);
-  }
-  assert (mussaAnalysis != 0);
-}
-void PathScene::loadMupa()
-{
-  QString caption("Load a mussa parameter file");
-  QString filter("Mussa Parameters (*.mupa)");
-  QString mupa_path = QFileDialog::getOpenFileName(this,
-                                                   caption, 
-                                                   QDir::currentPath(),
-                                                   filter);
-  // user hit cancel?
-  if (mupa_path.isNull()) 
-    return;
-  // try to load safely
-  try {
-    Mussa *m = new Mussa;
-    m->load_mupa_file(mupa_path.toStdString());
-    m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
-    // only switch mussas if we loaded without error
-    delete mussaAnalysis;
-    mussaAnalysis = m;
-    updateScene();
-  } catch (mussa_load_error e) {
-    QString msg("Unable to load ");
-    msg += mupa_path;
-    msg += "\n";
-    msg += e.what();
-    QMessageBox::warning(this, "Load Parameter", msg);
-  }
-  assert (mussaAnalysis != 0);
-}
-
-void PathScene::loadSavedAnalysis()
-{
-  QString caption("Load a previously run analysis");
-  QString muway_dir = QFileDialog::getExistingDirectory(this,
-                                                        caption, 
-                                                        QDir::currentPath());
-  // user hit cancel?
-  if (muway_dir.isNull()) 
-    return;
-  // try to safely load
-  try {
-    Mussa *m = new Mussa;
-    m->load(muway_dir.toStdString());
-    // only switch mussas if we loaded without error
-    delete mussaAnalysis;
-    mussaAnalysis = m;
-    updateScene();
-  } catch (mussa_load_error e) {
-    QString msg("Unable to load ");
-    msg += muway_dir;
-    msg += "\n";
-    msg += e.what();
-    QMessageBox::warning(this, "Load Parameter", msg);
-  }
-  assert (mussaAnalysis != 0);
-}
-
-void PathScene::setSoftThreshold(int threshold)
-{
-  if (mussaAnalysis->get_threshold() != threshold) {
-    mussaAnalysis->set_soft_thres(threshold);
-    mussaAnalysis->nway();
-    update();
-  }
+*/
 }
 
 ////////////////////
 // Rendering code
 void PathScene::initializeGL()
 {
-  glEnable(GL_DEPTH_TEST);
-  glClearColor(1.0, 1.0, 1.0, 0.0);
-  glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
-  glShadeModel(GL_FLAT);
+  GlTracks::initializeGL();
 }
 
 void PathScene::resizeGL(int width, int height)
 {
-  viewport_width = width;
-  viewport_height = height;
-  assert (geometry().width() == width);
-  assert (geometry().height() == height);
-  glViewport(0, 0, (GLsizei)width, (GLsizei)height);
-  glMatrixMode(GL_PROJECTION);
-  glLoadIdentity();
-  // I'm abusing this as Qt and OpenGL disagree about the direction of the
-  // y axis
-  glOrtho(curOrtho2d.left(), curOrtho2d.right(), 
-          curOrtho2d.top(), curOrtho2d.bottom(), 
-          -50.0, clipZ);
+  GlTracks::resizeGL(width, height);
 }
 
 void PathScene::paintGL()
 {
-  glClear(GL_COLOR_BUFFER_BIT|GL_DEPTH_BUFFER_BIT);
-
-  glPushMatrix();
-  glMatrixMode(GL_PROJECTION);
-  glLoadIdentity();
-  glOrtho(curOrtho2d.left(), curOrtho2d.right(), 
-          curOrtho2d.top(), curOrtho2d.bottom(), 
-          -50.0, clipZ);
-  glMatrixMode(GL_MODELVIEW);
-  mussaesque();
-  glEnable(GL_BLEND);
-  glDepthMask(GL_FALSE);
-  if (selectedMode && !drawingBand) {
-    glColor4f(0.6, 0.6, 0.6, 0.9);
-    glRectf(previousBand.x(), previousBand.y(),
-            previousBand.right(), previousBand.bottom());
-  }
-  glDepthMask(GL_TRUE);
-  glDisable(GL_BLEND);
-  glPopMatrix();
-  glFlush();
-}
-
-void PathScene::updateScene()
-{
-  // Delete old glsequences
-  // FIXME: does this actually free the memory from the new'ed GlSequences?
-  tracks.clear();
-
-  // save a reference to our GlSequences
-  GlSequence *gl_seq;
-  float y = mussaAnalysis->sequences().size() * 100 ;
-  float max_base_pairs = 0;
-  typedef vector<Sequence>::const_iterator seqs_itor_t;
-  for(seqs_itor_t seq_itor = mussaAnalysis->sequences().begin();
-      seq_itor != mussaAnalysis->sequences().end();
-      ++seq_itor)
-  {
-    y = y - 100;
-    gl_seq = new GlSequence(*seq_itor, mussaAnalysis->colorMapper());
-    gl_seq->setX(0);
-    gl_seq->setY(y);
-    if (gl_seq->length() > max_base_pairs ) max_base_pairs = gl_seq->length();
-    tracks.push_back( *gl_seq );
-  }
-  maxOrtho2d.setWidth(max_base_pairs + 100.0);
-  maxOrtho2d.setHeight((mussaAnalysis->sequences().size()) * 100 );
-  curOrtho2d = maxOrtho2d;
-  viewport_center = (curOrtho2d.right()-curOrtho2d.left())/2+curOrtho2d.left();
+  GlTracks::paintGL();
 }
 
+/*
 void PathScene::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
 {
   const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
@@ -408,122 +208,4 @@ void PathScene::mouseReleaseEvent( QMouseEvent *e)
 
   resizeGL(geometry().width(), geometry().height());
 }
-
-
-//////
-// openGl rendering code
-
-void PathScene::draw_tracks() const
-{
-  glPushMatrix();
-  glPushName(0);
-  for (vector<GlSequence>::size_type i = 0; i != tracks.size(); ++i )
-  {
-    glLoadName(i);
-    tracks[i].draw(curOrtho2d.left(), curOrtho2d.right());
-  }
-  glPopName();
-  glPopMatrix();
-}
-
-void PathScene::draw_lines() const
-{
-  GLfloat x;
-  GLfloat y;
-  GLuint pathid=0;
-  GLint objid=0;
-  bool reversed = false;
-  bool prevReversed = false;
-  const NwayPaths& nway = mussaAnalysis->paths();
-
-  glPushName(pathid);
-  glLineWidth(2);
-  vector<GlSequence>::const_iterator track_itor;
-  
-  typedef list<ExtendedConservedPath> conserved_paths;
-  typedef conserved_paths::const_iterator const_conserved_paths_itor;
-  for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
-      path_itor != nway.refined_pathz.end();
-      ++path_itor, ++objid)
-  {
-    track_itor = tracks.begin();
-    // since we were drawing to the start of a window, and opengl lines
-    // are centered around the two connecting points our lines were slightly
-    // offset. the idea of window_offset is to adjust them to the
-    // right for forward compliment or left for reverse compliment
-    // FIXME: figure out how to unit test these computations
-    GLfloat window_offset = (path_itor->window_size)/2.0;
-    
-    glBegin(GL_LINE_STRIP);
-    for (vector<int>::const_iterator sp_itor = path_itor->begin();
-         sp_itor != path_itor->end();
-         ++sp_itor, ++track_itor)
-    {
-      x = *sp_itor;
-      y = track_itor->y();
-      // at some point when we modify the pathz data structure to keep
-      // track of the score we can put grab the depth here.
-      //
-      // are we reverse complimented? 
-      if ( x>=0) {
-        reversed = false;
-      } else {
-        reversed = true;
-        x = -x; // make positive
-      }
-      if (!reversed)
-        x += window_offset; // move right for forward compliment
-      else
-        x -= window_offset; // move left for reverse compliment
-      // the following boolean implements logical xor
-      if ( (reversed || prevReversed) && (!reversed || !prevReversed)) { 
-        // we have a different orientation
-        if (not selectedMode or selectedPaths[objid] == true) {
-          // if we have nothing selected, or we're the highlight, be bright
-          glColor3f(0.0, 0.0, 1.0);
-        } else {
-          // else be dim
-          glColor3f(0.7, 0.7, 1.0);
-        }
-      } else {
-        // both current and previous path have the same orientation
-        if (not selectedMode or selectedPaths[objid] == true) {
-          glColor3f(1.0, 0.0, 0.0);
-        } else {
-          glColor3f(1.0, 0.7, 0.7);
-        }
-      }
-      prevReversed = reversed;
-      glVertex3f(x, y, -1.0);
-    }
-    glEnd();
-    glLoadName(++pathid);
-  }
-  glPopName();
-}
-
-GLuint PathScene::make_line_list()
-{
-  GLuint line_list = glGenLists(1);
-  glNewList(line_list, GL_COMPILE);
-
-  draw_lines();
-
-  glEndList();
-  return line_list;
-
-}
-
-void PathScene::mussaesque()
-{
-  //static GLuint theLines = make_line_list();
-
-  glInitNames();
-  glPushName(MussaPaths);
-  //glCallList(theLines);
-  draw_lines();
-  glLoadName(MussaTracks);
-  draw_tracks();
-  glPopName();
-}
-
+*/
index 547e113270fd7459aa8389452dd91430b0993a20..46c905ae7ffe20468d6001bcd82749de75fe0ab8 100644 (file)
@@ -9,61 +9,41 @@
 
 #include "alg/mussa.hpp"
 #include "alg/glsequence.hpp"
+#include "alg/gltracks.hpp"
 
 class QMouseEvent;
 class QRubberBand;
 
 /*! \brief Render mussa sequences and paths 
  */
-class PathScene: public QGLWidget
+class PathScene: public QGLWidget, public GlTracks
 {
   Q_OBJECT
 
 public: 
-  PathScene(Mussa *analysis=0,  QWidget *parent=0);
+  PathScene(QWidget *parent=0);
 
   QSize sizeHint() const;
-
-  Mussa* mussaAnalysis;
-  std::vector<GlSequence> tracks;
-
-  float left();
-  float right();
-  float viewportLeft();
-  float viewportRight();
-  float viewportCenter();
     
 public slots:
   void setClipPlane(int z);
   //! set the center of the current viewport
-  void setViewportX(float x);
+  void setViewportCenter(float x);
   //! set our magnification level
   void setZoom(int);
-  //! load motifs
-  void loadMotifList();
-  //! load a mussa parameter file (which specifies an analysis to run)
-  void loadMupa();
-  //! load a previously run analysis
-  void loadSavedAnalysis();
-  //! set the soft threshold used by the Nway_Path algorithm
-  void setSoftThreshold(int thres);
-  //! indicate that we should update our scene
-  void updateScene();
 
 signals:
   //! emitted when our analysis has changed
   void analysisUpdated();
   void viewportChanged();
 
-protected:
-  int viewport_height;
-  int viewport_width;
-  double clipZ;
-  int zoom;
-  QRectF maxOrtho2d;
-  QRectF curOrtho2d;
-  //! where the "center" of the viewport is
-  float viewport_center;
+private:
+  //GlTracks tracks_view;
+
+  void initializeGL();
+  void resizeGL(int height, int width);
+  void paintGL();
+
   //! true if we have a selection
   bool selectedMode;
   //! indicate which paths are selected
@@ -71,30 +51,19 @@ protected:
   //! which track is selected (it only makes sense to have one track selected).
   unsigned int selectedTrack;
 
-  void initializeGL();
-  void resizeGL(int width, int height);
-  void paintGL();
-  // recompute our current viewport dimensions, used by setViewportX & setZoom
-  void updateViewport(float left, int new_zoom);
-
-  void mussaesque();
-  //! draw all of our sequence tracks
-  void draw_tracks() const;
-  void draw_lines() const;
-  GLuint make_line_list();
   //! convert opengl selections into the list of paths we should highlight
   void processSelection(GLuint hits, GLuint buffer[], GLuint bufsize);
   //! Provide a logical name for a type discriminator for our glName stack
   enum FeatureType { MussaTracks, MussaPaths };
 
   //! \defgroup Selection
-  QRubberBand *rubberBand;
-  QPoint bandOrigin;
-  QRectF previousBand;
-  bool drawingBand;
-  void mousePressEvent(QMouseEvent *);
-  void mouseMoveEvent(QMouseEvent *);
-  void mouseReleaseEvent(QMouseEvent *);
+  //QRubberBand *rubberBand;
+  //QPoint bandOrigin;
+  //QRectF previousBand;
+  //bool drawingBand;
+  //void mousePressEvent(QMouseEvent *);
+  //void mouseMoveEvent(QMouseEvent *);
+  //void mouseReleaseEvent(QMouseEvent *);
 
 };
 #endif
index 6d9565b632c00c24465af8ee60f878347e49de03..03955a96b46d7e9b7a2f52c0070547af5ee6fbaf 100644 (file)
@@ -12,18 +12,19 @@ using namespace std;
 // whats the maximum reasonable range for a scrollbar
 const float max_scrollbar_range = 100000;
 
-PathWidget::PathWidget(PathScene *scene, QWidget *parent) :
+PathWidget::PathWidget(QWidget *parent) :
   QWidget(parent),
-  scene(scene),
   viewportBar(Qt::Horizontal)
 {
   QVBoxLayout *layout = new QVBoxLayout;
 
-  layout->addWidget(scene);
+  layout->addWidget(&scene);
   layout->addWidget(&viewportBar);
 
-  connect(&viewportBar, SIGNAL(valueChanged(int)), this, SLOT(setViewportX(int)));
-  connect(scene, SIGNAL(viewportChanged()), this, SLOT(updateScrollBar()));
+  connect(&viewportBar, SIGNAL(valueChanged(int)), 
+          this, SLOT(setViewportX(int)));
+  connect(&scene, SIGNAL(viewportChanged()), 
+          this, SLOT(updateScrollBar()));
   setLayout(layout);
 
   // sets range & scale
@@ -32,11 +33,11 @@ PathWidget::PathWidget(PathScene *scene, QWidget *parent) :
 
 void PathWidget::updateScrollBar()
 {
-  float max_right = scene->right();
-  float max_left = scene->left();
+  float max_right = scene.right();
+  float max_left = scene.left();
   float max_range = max_right - max_left;
-  float cur_left = scene->viewportLeft();
-  float cur_right = scene->viewportRight();
+  float cur_left = scene.viewportLeft();
+  float cur_right = scene.viewportRight();
   float cur_center = ((cur_right-cur_left)/2)+cur_left;
   // set range to min
   thumb = (int)cur_center;
@@ -44,10 +45,10 @@ void PathWidget::updateScrollBar()
   viewportBar.setValue(thumb);
 }
 
-void PathWidget::setViewportX(int x)
+void PathWidget::setViewportCenter(int x)
 {
   if (x != thumb) {
     thumb = x;
-    scene->setViewportX(thumb);
+    scene.setViewportCenter(thumb);
   }
 }
index 32c139604be06ea94be6e65e749573cdd02a97ed..08c46bb3148b690068da8b6e7765059caf9640bd 100644 (file)
@@ -3,30 +3,29 @@
 
 #include <QScrollBar>
 #include <QWidget>
-class PathScene;
+
+#include "qui/PathScene.hpp"
 
 class PathWidget : public QWidget
 {
   Q_OBJECT 
 
 public:
-  PathWidget(PathScene *, QWidget *parent=0);
+  PathWidget(QWidget *parent=0);
+  PathScene scene;
 
 public slots:
   //! update the scrollbar with current viewport information
   void updateScrollBar();
   //! update scene with the properly scalled scrollbar offset
-  void setViewportX(int x);
+  void setViewportCenter(int x);
 
 private:
-  PathScene *scene;
   QScrollBar viewportBar;
   int thumb;
 
   float range;
   float scale;
-
-
 };
 
 #endif
index 67ce139d267902c1f89187a1acb19bfc3385324c..7ffbadc5023dfa5546ec3f69d183b86bcfb80b3b 100644 (file)
@@ -6,62 +6,59 @@
 #include <QMenuBar>
 #include <QMessageBox>
 #include <QScrollBar>
-#include <QSpinBox>
 #include <QStatusBar>
 #include <QString>
-#include <QToolBar>
 #include <QWhatsThis>
 
 #include "qui/PathScene.hpp"
-#include "qui/PathWidget.hpp"
 #include "qui/PathWindow.hpp"
-#include "qui/ThresholdWidget.hpp"
 #include "qui/ImageSaveDialog.hpp"
+#include "mussa_exceptions.hpp"
 
 #include <iostream>
 
-PathWindow::PathWindow(Mussa *analysis, QWidget *) :
+using namespace std;
+
+PathWindow::PathWindow(Mussa *analysis_, QWidget *parent) :
+  QMainWindow(parent),
+  analysis(analysis_),
+  path_view(this),
+  mussaViewTB("Path Views"),
+  zoomBox(),
+  threshold(),
   closeAction(0) // initialize one of the pointers to null as a saftey flag
 {
-  scene = new PathScene(analysis, this);
-
   setupActions();
   setupMainMenu();
 
   //This next setWhatsThis function prevents
   // a segfault when using WhatsThis feature with 
   // opengl widget.
-  scene->setWhatsThis(tr("Mussa in OpenGL!"));
-  // make a widget so we can have a scroll bar
-  PathWidget *path_widget = new PathWidget(scene, this);
-  setCentralWidget(path_widget);
-
-  mussaViewTB = new QToolBar("Path Views");
-  mussaViewTB->addAction(toggleMotifsAction);
-
-  QSpinBox *zoom = new QSpinBox();
-  zoom->setWhatsThis("zoom magnification factor");
-  zoom->setRange(2,1000);
-  mussaViewTB->addWidget(zoom);
-  connect(zoom, SIGNAL(valueChanged(int)), scene, SLOT(setZoom(int)));
+  //scene->setWhatsThis(tr("Mussa in OpenGL!"));
+  setCentralWidget(&path_view);
+
+  mussaViewTB.addAction(toggleMotifsAction);
+
+  zoomBox.setWhatsThis("zoom magnification factor");
+  zoomBox.setRange(2,1000);
+  mussaViewTB.addWidget(&zoomBox);
+  connect(&zoomBox, SIGNAL(valueChanged(int)), 
+          &path_view.scene, SLOT(setZoom(int)));
   
-  ThresholdWidget *threshold = new ThresholdWidget;
-  threshold->setRange(19, 30);
-  threshold->setThreshold(19);
-  scene->setClipPlane(20);
+  threshold.setRange(19, 30);
+  threshold.setThreshold(19);
+  //scene->setClipPlane(20);
   // FIXME: for when we get the paths drawn at the appropriate depth
   //connect(threshold, SIGNAL(thresholdChanged(int)),
   //        scene, SLOT(setClipPlane(int)));
-  connect(threshold, SIGNAL(thresholdChanged(int)),
-          scene, SLOT(setSoftThreshold(int)));
-  mussaViewTB->addWidget(threshold);
+  //connect(&threshold, SIGNAL(thresholdChanged(int)),
+  //        &scene, SLOT(setSoftThreshold(int)));
+  mussaViewTB.addWidget(&threshold);
 
-  //Image Save Dialog
-  imageSaveDialog = new ImageSaveDialog(scene, this);
-
-  addToolBar(mussaViewTB);
+  addToolBar(&mussaViewTB);
 
   statusBar()->showMessage("Welcome to mussa", 2000);
+  updateAnalysis();
 }
 
 void PathWindow::setupActions()
@@ -91,15 +88,15 @@ void PathWindow::setupActions()
 
   loadMotifListAction = new QAction(tr("Load Motif List"), this);
   connect(loadMotifListAction, SIGNAL(triggered()), 
-          scene, SLOT(loadMotifList()));
+          this, SLOT(loadMotifList()));
   
   loadMupaAction = new QAction(tr("Load Mussa Parameters"), this);
   connect(loadMupaAction, SIGNAL(triggered()), 
-          scene, SLOT(loadMupa()));
+          this, SLOT(loadMupa()));
 
   loadSavedAnalysisAction = new QAction(tr("Load &Analysis"), this);
   connect(loadSavedAnalysisAction, SIGNAL(triggered()), 
-          scene, SLOT(loadSavedAnalysis()));
+          this, SLOT(loadSavedAnalysis()));
   loadSavedAnalysisAction->setIcon(QIcon("icons/fileopen.png"));
 
   saveMotifListAction = new QAction(tr("Save Motifs"), this);
@@ -178,19 +175,109 @@ void PathWindow::createSubAnalysis()
   NotImplementedBox();
 }
 
+
+void PathWindow::loadMotifList()
+{
+  QString caption("Load a motif list");
+  QString filter("Motif list(*.txt *.mtl)");
+  QString path = QFileDialog::getOpenFileName(this,
+                                                   caption, 
+                                                   QDir::currentPath(),
+                                                   filter);
+  // user hit cancel?
+  if (path.isNull()) 
+    return;
+  // try to load safely
+  try {
+    analysis->load_motifs(path.toStdString());
+  } catch (runtime_error e) {
+    QString msg("Unable to load ");
+    msg += path;
+    msg += "\n";
+    msg += e.what();
+    QMessageBox::warning(this, "Load Motifs", msg);
+  }
+  assert (analysis != 0);
+}
+
 void PathWindow::saveMotifList()
 {
   NotImplementedBox();
 }
 
+void PathWindow::loadMupa()
+{
+  QString caption("Load a mussa parameter file");
+  QString filter("Mussa Parameters (*.mupa)");
+  QString mupa_path = QFileDialog::getOpenFileName(this,
+                                                   caption, 
+                                                   QDir::currentPath(),
+                                                   filter);
+  // user hit cancel?
+  if (mupa_path.isNull()) 
+    return;
+  // try to load safely
+  try {
+    Mussa *m = new Mussa;
+    m->load_mupa_file(mupa_path.toStdString());
+    m->analyze(0, 0, Mussa::TransitiveNway, 0.0);
+    // only switch mussas if we loaded without error
+    delete analysis;
+    analysis = m;
+    updateAnalysis();
+  } catch (mussa_load_error e) {
+    QString msg("Unable to load ");
+    msg += mupa_path;
+    msg += "\n";
+    msg += e.what();
+    QMessageBox::warning(this, "Load Parameter", msg);
+  }
+  assert (analysis != 0);
+}
+
+void PathWindow::loadSavedAnalysis()
+{
+  QString caption("Load a previously run analysis");
+  QString muway_dir = QFileDialog::getExistingDirectory(this,
+                                                        caption, 
+                                                        QDir::currentPath());
+  // user hit cancel?
+  if (muway_dir.isNull()) 
+    return;
+  // try to safely load
+  try {
+    Mussa *m = new Mussa;
+    m->load(muway_dir.toStdString());
+    // only switch mussas if we loaded without error
+    delete analysis;
+    analysis = m;
+    updateAnalysis();
+  } catch (mussa_load_error e) {
+    QString msg("Unable to load ");
+    msg += muway_dir;
+    msg += "\n";
+    msg += e.what();
+    QMessageBox::warning(this, "Load Parameter", msg);
+  }
+  assert (analysis != 0);
+}
+
+void PathWindow::setSoftThreshold(int threshold)
+{
+  if (analysis->get_threshold() != threshold) {
+    analysis->set_soft_thres(threshold);
+    analysis->nway();
+    updateLinks();
+    update();
+  }
+}
+
 void PathWindow::showMussaToolbar()
 {
-  std::clog << "isVis?" << mussaViewTB->isVisible() <<std::endl;
-  if (mussaViewTB->isVisible())
-    mussaViewTB->hide();
+  if (mussaViewTB.isVisible())
+    mussaViewTB.hide();
   else
-    mussaViewTB->show();
-  std::clog << "isVis?" << mussaViewTB->isVisible() <<std::endl;
+    mussaViewTB.show();
 }
 
 void PathWindow::toggleMotifs()
@@ -206,9 +293,68 @@ void PathWindow::NotImplementedBox()
 void PathWindow::promptSaveOpenGlPixmap()
 {
   QSize size;
-  size = scene->size();
-  imageSaveDialog->setSize(size.width(), size.height());
-  int result = imageSaveDialog->exec();
-  std::cout << "Result: " << result << "\n";
+  size = path_view.scene.size();
+  //Image Save Dialog
+  ImageSaveDialog imageSaveDialog(&path_view.scene, this);
+  imageSaveDialog.setSize(size.width(), size.height());
+  int result = imageSaveDialog.exec();
+  cout << "Result: " << result << "\n";
+}
+
+void PathWindow::updateAnalysis()
+{
+  cout << "analysis updated" << endl;
+  path_view.scene.clear();
+  const vector<Sequence>& seqs = analysis->sequences();
+  for(vector<Sequence>::const_iterator seq_i = seqs.begin();
+      seq_i != seqs.end();
+      ++seq_i)
+  {
+    path_view.scene.push_sequence(*seq_i);
+  }
+  updateLinks();
+}
+
+void PathWindow::updateLinks()
+{
+  path_view.scene.clear_links();
+  bool reversed = false;
+  const NwayPaths& nway = analysis->paths();
+
+  typedef list<ExtendedConservedPath> conserved_paths;
+  typedef conserved_paths::const_iterator const_conserved_paths_itor;
+  for(const_conserved_paths_itor path_itor = nway.refined_pathz.begin();
+      path_itor != nway.refined_pathz.end();
+      ++path_itor)
+  {
+    // since we were drawing to the start of a window, and opengl lines
+    // are centered around the two connecting points our lines were slightly
+    // offset. the idea of window_offset is to adjust them to the
+    // right for forward compliment or left for reverse compliment
+    // FIXME: figure out how to unit test these computations
+    //GLfloat window_offset = (path_itor->window_size)/2.0;
+
+    size_t track_len = path_itor->track_indexes.size();
+    vector<int> normalized_path;
+    normalized_path.reserve(track_len);
+    vector<bool> rc_flags(false, track_len);
+    for (size_t track_i=0; track_i != track_len; ++track_i)
+    {
+      int x = path_itor->track_indexes[track_i];
+      // at some point when we modify the pathz data structure to keep
+      // track of the score we can put grab the depth here.
+      //
+      // are we reverse complimented?
+      if ( x>=0) {
+        reversed = false;
+      } else {
+        reversed = true;
+        x = -x; // make positive
+      }
+      normalized_path.push_back(x);
+      rc_flags.push_back(reversed);
+    }
+    path_view.scene.link(normalized_path, rc_flags, path_itor->window_size);
+  }
 }
 
index 96048b8b0f57c66b34ffed48134836290a5f20cb..65bafdfaeb73726991fbc9c70613af6d098b9e7a 100644 (file)
@@ -1,11 +1,17 @@
 #ifndef _PATHWINDOW_H_
 #define _PATHWINDOW_H_
 
+
+
 #include <QMainWindow>
 #include <QPixmap>
+#include <QSpinBox>
+#include <QToolBar>
+
+#include "qui/PathWidget.hpp"
+#include "qui/ThresholdWidget.hpp"
+
 class QAction;
-class PathScene;
-class ImageSaveDialog;
 class Mussa;
 
 class PathWindow : public QMainWindow
@@ -29,20 +35,31 @@ public slots:
 
   //! \defgroup MotifHandling Handling of motif lists
   //\@{
+  //! load motifs
+  void loadMotifList();
   void saveMotifList();
   void toggleMotifs();
   //\@}
 
+  //! load a mussa parameter file (which specifies an analysis to run)
+  void loadMupa();
+  //! load a previously run analysis
+  void loadSavedAnalysis();
+  //! set the soft threshold used by the Nway_Path algorithm
+  void setSoftThreshold(int thres);
+
   void showMussaToolbar();
   
   void promptSaveOpenGlPixmap();
 
 protected:
+  Mussa *analysis;
   // display our wonderful mussa output
-  PathScene *scene;
-  QToolBar *mussaViewTB;
-  ImageSaveDialog *imageSaveDialog;
-  
+  PathWidget path_view;
+  QToolBar mussaViewTB;
+  QSpinBox zoomBox;
+  ThresholdWidget threshold;
+
   QAction *aboutAction;
   QAction *closeAction;
   QAction *createNewAnalysisAction;
@@ -62,6 +79,10 @@ protected:
   void setupMainMenu();
   //! stub function to fill in QActions
   void NotImplementedBox();
+  //! update the PathScene with our analysis
+  void updateAnalysis();
+  //! update the view of conserved windows
+  void updateLinks();
 };
 
 #endif