#include "alg/gltracks.hpp"
+#include "mussa_exceptions.hpp"
#include <iostream>
#include <stdexcept>
glFlush();
}
+void GlTracks::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
+{
+ GLuint *ptr;
+ GLuint names;
+ GLuint consumed_names = 0;
+ float z1;
+ float z2;
+ GLuint objtype;
+ GLuint objid;
+ GLuint path_index = 0;
+ GLuint pair_key_0 = 0;
+ GLuint pair_key_1 = 0;
+
+ selectedPaths.clear();
+ selectedTracks.clear();
+
+ std::cout << "hits = " << hits << std::endl;
+ ptr = (GLuint *) buffer;
+ if (hits > 0)
+ selectedMode = true;
+ for (GLuint i=0; i < hits; ++i)
+ {
+ if ((i + 5) > bufsize) {
+ std::clog << "*** selection overflow***" << std::endl;
+ } else {
+ consumed_names = 0;
+ names = *ptr++;
+ z1 = ((float)*ptr++)/0x7fffffff;
+ z2 = ((float)*ptr++)/0x7fffffff;
+ objtype = *ptr++; ++consumed_names;
+ switch (objtype) {
+ case MussaSegment:
+ path_index = *ptr++; ++consumed_names;
+ pair_key_0 = *ptr++; ++consumed_names;
+ pair_key_1 = *ptr++; ++consumed_names;
+ if (path_index < path_segments.size()) {
+ segment_key k(pair_key_0, pair_key_1);
+ pair_segment_map::iterator psm_i;
+ psm_i = path_segments[path_index].find(k);
+ if (psm_i != path_segments[path_index].end()) {
+ Segment &seg = psm_i->second;
+ selectedPaths.insert(seg.path_ids.begin(), seg.path_ids.end());
+ }
+ // else something else is wrong
+ } else {
+ // something wasn't right
+ clog << "invalid path_index " << path_index
+ << " should have been [0,"<<path_segments.size()
+ << ") " << endl;
+ }
+ break;
+ case MussaTrack:
+ objid = *ptr++; ++consumed_names;
+ selectedTracks.insert(objid);
+ break;
+ default:
+ cout << "unknown type " << objtype << " ";
+ for(; consumed_names < names; ++consumed_names) {
+ cout << consumed_names << "," << *ptr++ << " ";
+ }
+ cout << endl;
+ break;
+ }
+ }
+ }
+}
+
+void GlTracks::selectRegion(int top, int left, int bottom, int right)
+{
+ GLfloat x_scale = cur_ortho.width()/((float)viewport_size.x);
+ GLfloat y_scale = cur_ortho.height()/((float)viewport_size.y);
+ GLfloat x_left = cur_ortho.left + (left*x_scale);
+ GLfloat x_right = right * x_scale;
+
+ if (top > bottom) {
+ // woah, someone gave us a rectangle with the origin in the lower left
+ int temp = top;
+ bottom = top;
+ top = temp;
+ }
+ // swap the orientation of canvas coordinates
+ GLfloat y_top = cur_ortho.top-(bottom*y_scale);
+ GLfloat y_bottom = cur_ortho.top - top * y_scale;
+ selectedRegion = rect<float>(y_top, x_left, y_bottom, x_right);
+
+ // hopefully this will make a buffer big enough to receive
+ // everything being selected
+ //const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
+ //const GLuint select_buf_size = 1 + 5 * (pathz_count + tracks.size());
+ const GLuint select_buf_size = 500000;
+ GLuint selectBuf[select_buf_size];
+ glSelectBuffer(select_buf_size, selectBuf);
+ GLint hits;
+
+ (void)glRenderMode(GL_SELECT);
+ glPushMatrix();
+ glMatrixMode(GL_PROJECTION);
+ glLoadIdentity();
+ glOrtho(x_left, x_right, y_top, y_bottom, -50.0, 50.0);
+ glMatrixMode(GL_MODELVIEW);
+ glLoadIdentity();
+
+ draw();
+
+ glFlush();
+ glPopMatrix();
+ hits = glRenderMode(GL_RENDER);
+ processSelection(hits, selectBuf, select_buf_size);
+}
+
float GlTracks::left() const
{
return max_ortho.left;
void GlTracks::clear()
{
- //clear_links();
- //path_segments.clear();
+ clear_links();
+ path_segments.clear();
track_container.clear();
}
void GlTracks::push_sequence(GlSequence &gs)
{
- //clear_links();
+ clear_links();
pathid = 0;
track_container.push_back(gs);
update_layout();
y2 += track_container[track_i+1].height()/2;
Segment s(prev_x, y1, *path_i, y2, prev_rc);
- s.path_ids.push_back(pathid);
+ s.path_ids.insert(pathid);
path_segments[track_i][p] = s;
} else {
//found
- found_segment->second.path_ids.push_back(pathid);
+ found_segment->second.path_ids.insert(pathid);
}
prev_x = *path_i;
prev_rc = *rc_i;
void GlTracks::draw() const
{
glMatrixMode(GL_MODELVIEW);
- //glInitNames();
- //glPushName(MussaPaths);
+ glInitNames();
+ glPushName(MussaSegment);
draw_segments();
+ glLoadName(MussaTrack);
draw_tracks();
+ glPopName();
+ // a selection shouldn't have a glName associated with it
draw_selection();
- //glPopName();
}
void GlTracks::draw_selection() const
{
- /* draw selection box
+ // draw selection box
glEnable(GL_BLEND);
glDepthMask(GL_FALSE);
- if (selectedMode && !drawingBand) {
+ if (selectedMode) {
glColor4f(0.6, 0.6, 0.6, 0.9);
- glRectf(previousBand.x(), previousBand.y(),
- previousBand.right(), previousBand.bottom());
+ glRectf(selectedRegion.left, selectedRegion.top,
+ selectedRegion.right, selectedRegion.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)
+ for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
{
- seq_i->draw(cur_ortho.left, cur_ortho.right);
+ glPushName(track_i);
+ track_container[track_i].draw(cur_ortho.left, cur_ortho.right);
+ glPopName();
}
}
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;
psmv_i != path_segments.end();
++psmv_i)
{
+ path_segment_map_vector::difference_type path_index;
+ path_index = psmv_i - path_segments.begin();
// 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;
psm_i != psmv_i->end();
++psm_i)
{
+ // grab the index into our segment map
+ const segment_key& key = psm_i->first;
// 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
+ vector<int> selected;
+ set_intersection(selectedPaths.begin(), selectedPaths.end(),
+ s.path_ids.begin(), s.path_ids.end(),
+ back_inserter(selected));
+
if (not s.reversed) {
- glColor3f(1.0, 0.0, 0.0);
+ if (selectedPaths.size() == 0 or selected.size() > 0) {
+ glColor3f(1.0, 0.0, 0.0);
+ } else {
+ glColor3f(1.0, 0.8, 0.8);
+ }
} else {
- glColor3f(0.0, 0.0, 1.0);
+ if (selectedPaths.size() == 0 or selected.size() > 0) {
+ glColor3f(0.0, 0.0, 1.0);
+ } else {
+ glColor3f(0.8, 0.8, 1.0);
+ }
}
+ // save the multipart name for our segment
+ glPushName(path_index); glPushName(key.first); glPushName(key.second);
+ glBegin(GL_LINES);
glVertex3f(s.start.x, s.start.y, -1);
glVertex3f(s.end.x, s.end.y, -1);
+ glEnd();
+ // clear the names
+ glPopName(); glPopName(); glPopName();
}
}
- glEnd();
}
#define _GLTRACKS_H_
#include <map>
+#include <set>
#include <vector>
#include "alg/annotation_colors.hpp"
//! render our scene
void paintGL() const;
+ //! select a region (using canvas coordinates)
+ void GlTracks::selectRegion(int top, int left, int bottom, int right);
+
//! max world left coordinate
float left() const;
//! max world right coordinate
//! define a path
void link(std::vector<int> path, std::vector<bool> isRC, int length);
+ //! Provide a logical name for a type discriminator for our glName stack
+ enum FeatureType { MussaTrack, MussaSegment };
+
//! a useful point class
template<class T> struct point {
T x;
T bottom;
T right;
+ rect() {}
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; }
point<float> start;
point<float> end;
bool reversed;
- std::list<int> path_ids;
+ std::set<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)
//! determine where all the tracks should be placed
void update_layout();
+ //! convert opengl selections into the list of paths we should highlight
+ void processSelection(GLuint hits, GLuint buffer[], GLuint bufsize);
+
//! master scene drawing function
/*! draw is broken out for the opengl selection code
*/
std::vector<GlSequence> track_container;
//! counter for each path added to us via connect
int pathid;
+
+protected:
+ //! where to draw our box
+ rect<float> selectedRegion;
+ //! true if we have a selection
+ bool selectedMode;
+ //! indicate which paths are selected
+ std::set<int> selectedPaths;
+ //! which track is selected (it only makes sense to have one track selected).
+ std::set<int> selectedTracks;
+
};
#endif
--- /dev/null
+#include <boost/test/auto_unit_test.hpp>
+#include <boost/assign/std/vector.hpp>
+using namespace boost::assign;
+
+#include <string>
+#include <list>
+#include <vector>
+
+#include "alg/annotation_colors.hpp"
+#include "alg/gltracks.hpp"
+#include "alg/sequence.hpp"
+
+using namespace std;
+
+BOOST_AUTO_TEST_CASE ( gltracks_connect )
+{
+ string s0("AAGGCCTT");
+ string s1("TTGGCCAA");
+ string s2("GATTACAA");
+ Sequence seq0(s0);
+ Sequence seq1(s1);
+ Sequence seq2(s2);
+
+ GlTracks gt;
+ gt.push_sequence(seq0);
+ gt.push_sequence(seq1);
+ gt.push_sequence(seq2);
+
+ // make up some sample data
+ vector<bool> rc;
+ rc += false, false, false;
+ vector<int> path;
+ path += 1,1,1; gt.link(path, rc, 1);
+ path.clear(); path += 1,1,3; gt.link(path, rc, 1);
+ path.clear(); path += 2,3,3; gt.link(path, rc, 1);
+ path.clear(); path += 3,3,3; gt.link(path, rc, 1);
+
+ BOOST_CHECK_EQUAL( gt.path_segments.size(), 2 );
+ GlTracks::segment_key p(1, 1);
+ GlTracks::pair_segment_map::iterator psm_i = gt.path_segments[0].find(p);
+ BOOST_CHECK( psm_i != gt.path_segments[0].end() );
+ BOOST_CHECK_EQUAL( psm_i->second.path_ids.size(), 2 );
+
+ gt.clear();
+ BOOST_CHECK_EQUAL( gt.path_segments.size(), 0 );
+}
+
using namespace std;
PathScene::PathScene(QWidget *parent)
- : QGLWidget(parent)
- //selectedMode(false),
- //rubberBand(0),
- //drawingBand(false)
+ : QGLWidget(parent),
+ rubberBand(0),
+ drawingBand(false)
{
}
QSize PathScene::sizeHint() const
{
- return QSize(GlTracks::viewportHeight(), GlTracks::viewportWidth());
+ return QSize((int)GlTracks::viewportHeight(), (int)GlTracks::viewportWidth());
}
void PathScene::setViewportCenter(float x)
GlTracks::paintGL();
}
-/*
-void PathScene::processSelection(GLuint hits, GLuint buffer[], GLuint bufsize)
-{
- const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
- GLuint *ptr;
- GLuint names;
- float z1;
- float z2;
- GLuint objtype;
- GLuint objid;
-
- selectedPaths.clear();
- selectedPaths.reserve(pathz_count);
- selectedPaths.insert(selectedPaths.begin(), pathz_count, false);
- selectedTrack = 0x7fffffff;
-
- std::cout << "hits = " << hits << " " << pathz_count << std::endl;
- ptr = (GLuint *) buffer;
- if (hits > 0)
- selectedMode = true;
- for (GLuint i=0; i < hits; ++i)
- {
- if ((i + 5) > bufsize) {
- std::clog << "*** selection overflow***" << std::endl;
- } else {
- names = *ptr++;
- z1 = ((float)*ptr++)/0x7fffffff;
- z2 = ((float)*ptr++)/0x7fffffff;
- objtype = *ptr++;
- objid = *ptr++;
- if (names != 2) {
- std::clog << "wrong number of glNames, selection is having trouble ";
- std::clog << " got " << names << std::endl;
- std::clog << " names: " ;
- for (GLuint j = 0 ; j < names-2; ++j) {
- std::clog << *ptr++ << " ";
- }
- std::clog << endl;
- return;
- }
- switch (objtype) {
- case MussaPaths:
- selectedPaths[objid] = true;
- break;
- case MussaTracks:
- if (objid < selectedTrack) {
- selectedTrack = objid;
- }
- break;
- }
- }
- }
-}
-
void PathScene::mousePressEvent( QMouseEvent *e)
{
drawingBand = true;
- std::cout << "x=" << e->x() << " y=" << e->y() << std::endl;
selectedMode = false;
bandOrigin = e->pos();
rubberBand->setGeometry(QRect(bandOrigin, e->pos()).normalized());
}
-void dumpRect(const QRect &r)
-{
- std::cout << "x=" << r.x() << " y=" << r.y()
- << " w=" << r.width() << " h=" << r.height() << std::endl;
-}
-
void PathScene::mouseReleaseEvent( QMouseEvent *e)
{
drawingBand = false;
rubberBand->hide();
QRect r = QRect(bandOrigin, e->pos()).normalized();
bandOrigin = r.topLeft();
- std::cout << "band ";
- dumpRect(r);
-
- std::cout << "window ";
- dumpRect(geometry());
-
- GLfloat x_scale = curOrtho2d.width()/((float)geometry().width());
- GLfloat y_scale = curOrtho2d.height()/((float)geometry().height());
- GLfloat x_left = curOrtho2d.left() + (r.x()*x_scale);
- GLfloat x_right = x_left + r.width() * x_scale;
- // using QRectF with Y axis swapped
- GLfloat y_top = curOrtho2d.bottom()-(r.y()*y_scale);
- GLfloat y_bottom = y_top - r.height() * y_scale;
- previousBand.setCoords(x_left, y_top, x_right, y_bottom);
- std::cout << x_left << " " << x_right << " " << y_top << " " << y_bottom
- << std::endl;
-
- // hopefully this will make a buffer big enough to receive
- // everything being selected
- const size_t pathz_count = mussaAnalysis->paths().refined_pathz.size();
- const GLuint select_buf_size = 1 + 5 * (pathz_count + tracks.size()) ;
- GLuint selectBuf[select_buf_size];
- glSelectBuffer(select_buf_size, selectBuf);
- GLint hits;
-
- (void)glRenderMode(GL_SELECT);
- glPushMatrix();
- glMatrixMode(GL_PROJECTION);
- glLoadIdentity();
- glOrtho(x_left, x_right, y_top, y_bottom, -50.0, 50.0);
- glMatrixMode(GL_MODELVIEW);
- glLoadIdentity();
-
- mussaesque();
- glFlush();
-
- glPopMatrix();
- hits = glRenderMode(GL_RENDER);
- processSelection(hits, selectBuf, select_buf_size);
-
- resizeGL(geometry().width(), geometry().height());
+
+ selectRegion(r.top(), r.left(), r.bottom(), r.right());
}
-*/
void viewportChanged();
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
- std::vector<bool> selectedPaths;
- //! which track is selected (it only makes sense to have one track selected).
- unsigned int selectedTrack;
-
- //! 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;
+ bool drawingBand;
+ void mousePressEvent(QMouseEvent *);
+ void mouseMoveEvent(QMouseEvent *);
+ void mouseReleaseEvent(QMouseEvent *);
};
#endif