return seq_y;
}
+GLfloat GlSequence::height() const
+{
+ return seq_height;
+}
+
GLfloat GlSequence::length() const
{
return seq.size();
glVertex3f(right, top, z);
glEnd();
}
+
void GlSequence::draw_track(GLfloat left, GLfloat right) const
{
glColor3fv(drawColor.get());
}
-
const int PT = 1;
const int STROKE = 2;
const int END =3;
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;
--- /dev/null
+#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();
+}
--- /dev/null
+#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
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))
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
#include <list>
#include <string>
#include <vector>
+#include <iostream>
// Sequence data class
//! 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,
test_conserved_path.cpp \
test_flp.cpp \
test_glsequence.cpp \
+ test_gltracks.cpp \
test_color.cpp \
test_main.cpp \
test_mussa.cpp \
#include <boost/test/auto_unit_test.hpp>
#include <boost/test/floating_point_comparison.hpp>
#include <string>
+#include <sstream>
#include "alg/color.hpp"
BOOST_CHECK_CLOSE (colors[Color::BlueChannel ], dotthree, tolerance );
BOOST_CHECK_CLOSE (colors[Color::AlphaChannel ], dotfour, tolerance );
}
-
-
alg/conserved_path.hpp \
alg/flp.hpp \
alg/glsequence.hpp \
+ alg/gltracks.hpp \
alg/mussa.hpp \
alg/nway_paths.hpp \
alg/parse_options.hpp \
alg/flp.cpp \
alg/flp_seqcomp.cpp \
alg/glsequence.cpp \
+ alg/gltracks.cpp \
alg/mussa.cpp \
alg/nway_entropy.cpp \
alg/nway_other.cpp \
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();
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();
-}
-
+*/
#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
//! 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
// 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
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;
viewportBar.setValue(thumb);
}
-void PathWidget::setViewportX(int x)
+void PathWidget::setViewportCenter(int x)
{
if (x != thumb) {
thumb = x;
- scene->setViewportX(thumb);
+ scene.setViewportCenter(thumb);
}
}
#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
#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()
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);
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()
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);
+ }
}
#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
//! \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;
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