#include "alg/glseqbrowser.hpp"
#include "mussa_exceptions.hpp"
+#include <math.h>
#include <iostream>
#include <sstream>
#include <stdexcept>
viewport_center(gt.viewport_center),
zoom_level(gt.zoom_level),
color_mapper(gt.color_mapper),
- track_container(gt.track_container)
+ track_container(gt.track_container),
+ path_segments(gt.path_segments)
{
}
}
break;
case MussaTrack:
- {
+ {
objid = *ptr++; ++consumed_names;
- int left = track_container[objid].leftbase(r.left);
- int right = track_container[objid].rightbase(r.right);
+ int left = track_container[objid]->leftbase(r.left);
+ int right = track_container[objid]->rightbase(r.right);
// the static_cast should be ok, since basepairs line up on
// integral values
//TrackRegion track(objid, left, right);
track.set(objid, left, right);
selected_tracks.push_back(track);
- }
+ //clog << "selected track " << objid
+ // << "(" << left << ", " << right << ")" << endl;
+ }
break;
default:
cout << "unknown type " << objtype << " ";
void GlSeqBrowser::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 = cur_ortho.left + (right * x_scale);
+ GLfloat x_left = viewportXtoWorldX(left);
+ GLfloat x_right = viewportXtoWorldX(right);cur_ortho.left;
if (top > bottom) {
// woah, someone gave us a rectangle with the origin in the lower left
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;
+ GLfloat y_top = viewportYtoWorldY(bottom);
+ GLfloat y_bottom = viewportYtoWorldY(top);
selectedRegion = rect<float>(y_top, x_left, y_bottom, x_right);
// hopefully this will make a buffer big enough to receive
processSelection(hits, selectBuf, select_buf_size, selectedRegion);
}
+void GlSeqBrowser::clearSelection()
+{
+ selected_paths.clear();
+ selected_tracks.clear();
+ selectedMode = false;
+}
+
float GlSeqBrowser::border() const
{
return border_width;
{
return cur_ortho.left;
} else {
- vector<GlSequence>::const_iterator track_i = track_container.begin();
- left = track_i->x();
+ vector<boost::shared_ptr<GlSequence> >::const_iterator track_i = track_container.begin();
+ left = (*track_i)->x();
for( ; track_i != track_container.end(); ++track_i)
{
- if (track_i->x() < left) {
- left = track_i->x();
+ if ((*track_i)->x() < left) {
+ left = (*track_i)->x();
}
}
return left-border_width;
if (track_container.size() == 0) {
return cur_ortho.right;
} else {
- vector<GlSequence>::const_iterator track_i = track_container.begin();
- right = track_i->right();
+ vector<boost::shared_ptr<GlSequence> >::const_iterator track_i = track_container.begin();
+ right = (*track_i)->right();
for( ; track_i != track_container.end(); ++track_i) {
- if (track_i->right() > right)
- right = track_i->right();
+ if ((*track_i)->right() > right)
+ right = (*track_i)->right();
}
return right+border_width;
}
}
+float GlSeqBrowser::get_pixel_width() const
+{
+ GLint viewport[4];
+ glGetIntegerv(GL_VIEWPORT, viewport);
+ GLint vp_width = viewport[3]; // grab the viewport width
+
+ return round((cur_ortho.right-cur_ortho.left)/vp_width);
+}
+
void GlSeqBrowser::setViewportCenter(float x)
{
update_viewport(x, zoom_level);
return cur_ortho.right - cur_ortho.left;
}
+int GlSeqBrowser::viewportPixelHeight() const
+{
+ return viewport_size.y;
+}
+
+int GlSeqBrowser::viewportPixelWidth() const
+{
+ return viewport_size.x;
+}
+
double GlSeqBrowser::zoomOut()
{
return zoom_level;
}
-void GlSeqBrowser::setColorMapper(AnnotationColors& cm)
+void GlSeqBrowser::setColorMapper(AnnotationColorsRef cm)
{
color_mapper = cm;
}
-AnnotationColors& GlSeqBrowser::colorMapper()
+const AnnotationColorsRef GlSeqBrowser::colorMapper()
{
return color_mapper;
}
void GlSeqBrowser::clear()
{
+ clear_selection();
clear_links();
path_segments.clear();
track_container.clear();
}
-void GlSeqBrowser::push_sequence(const Sequence &s)
+void GlSeqBrowser::clear_selection()
+{
+ selectedMode = false;
+ selectedRegion.clear();
+ selected_paths.clear();
+ selected_tracks.clear();
+}
+
+void GlSeqBrowser::push_sequence(const Sequence& s)
{
- GlSequence gs(s, color_mapper);
+ GlSequenceRef gs(new GlSequence(s, color_mapper));
push_sequence(gs);
}
-void GlSeqBrowser::push_sequence(GlSequence &gs)
+void GlSeqBrowser::push_sequence(SequenceRef s)
{
+ GlSequenceRef gs(new GlSequence(*s, color_mapper));
+ push_sequence(gs);
+}
+
+void GlSeqBrowser::push_sequence(GlSequence gs)
+{
+ GlSequenceRef new_gs(new GlSequence(gs));
+ push_sequence(new_gs);
+}
+
+void GlSeqBrowser::push_sequence(GlSequenceRef gs)
+{
+ ColorRef default_color(GlSequence::default_gene_color());
+ GlSequenceRef new_gs(new GlSequence(gs));
+ new_gs->update_annotation_draw_function("gene", draw_narrow_track, default_color);
+ // mark where the sequence is
+ new_gs->add_annotations_for_defined_sequence(draw_summarized_track);
+
clear_links();
- track_container.push_back(gs);
+ track_container.push_back(new_gs);
update_layout();
if (track_container.size() > 1)
path_segments.push_back(pair_segment_map());
}
-const std::vector<GlSequence>& GlSeqBrowser::sequences() const
+const std::vector<GlSequenceRef >& GlSeqBrowser::sequences() const
{
return track_container;
}
}
void
-GlSeqBrowser::link(const vector<int>& path, const vector<bool>& rc, int )
+GlSeqBrowser::link(const vector<int>& path, const vector<bool>& rc, int length)
{
if (path.size() < 2) {
// should i throw an error instead?
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;
+ 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;
bool rcFlag = (prev_rc or *rc_i) and !(prev_rc and *rc_i);
- Segment s(prev_x, y1, *path_i, y2, rcFlag);
+ Segment s(prev_x, y1, *path_i, y2, rcFlag, length);
s.path_ids.insert(pathid);
path_segments[track_i][p] = s;
} else {
//found
found_segment->second.path_ids.insert(pathid);
+ // make each segment the size of the largest of any link between these
+ // two bases
+ if (found_segment->second.length < length) {
+ found_segment->second.length = length;
+ }
}
prev_x = *path_i;
prev_rc = *rc_i;
++pathid;
}
+void GlSeqBrowser::setSelectedPaths(std::vector<int> paths)
+{
+ selected_paths.clear();
+ for(std::vector<int>::iterator itor = paths.begin();
+ itor != paths.end();
+ ++itor)
+ {
+ selected_paths.insert(*itor);
+ }
+}
+
const set<int>& GlSeqBrowser::selectedPaths() const
{
return selected_paths;
}
+void GlSeqBrowser::appendSelectedTrack(GLuint track, int start, int stop)
+{
+ selected_tracks.push_back(TrackRegion(track, start, stop));
+}
+
+list<TrackRegion> GlSeqBrowser::selectedTracks() const
+{
+ return selected_tracks;
+}
+
//! copy sequence from selected track using formating function
-void GlSeqBrowser::copySelectedTracks(std::string& copy_buffer,
- format_track formatter)
+template<class Item>
+size_t GlSeqBrowser::copySelectedTracks(std::list<Item>& result,
+ Item (*formatter)(const Sequence& s, int left, int right))
{
- copy_buffer.clear();
+ size_t base_pairs_copied = 0;
+ result.clear();
for(selected_track_iterator track_i = selected_tracks.begin();
track_i != selected_tracks.end();
<< endl;
} else {
// we should be safe
- const Sequence& seq = track_container[track_index].sequence();
- copy_buffer += formatter(seq, track_i->left, track_i->right);
+ Sequence seq(*track_container[track_index]);
+ result.push_back(formatter(seq, track_i->left, track_i->right));
+ base_pairs_copied += max(track_i->right-track_i->left, 0);
}
}
+ return base_pairs_copied;
}
-//! copy sequence from selected tracks as plain sequences
-void GlSeqBrowser::copySelectedTracksAsString(std::string& copy_buffer)
+//! copy sequence from selected tracks as FASTA sequences
+size_t GlSeqBrowser::copySelectedTracksAsFasta(std::string& copy_buffer)
{
- struct AsString {
+ std::list<std::string> result;
+ struct AsFasta {
static string formatter(const Sequence& seq, int left, int right)
{
stringstream s;
- s << seq.subseq(left, right-left+1) << std::endl;
+ s << ">" << seq.get_fasta_header()
+ << "|" << "subregion=" << left << "-" << right+1
+ << std::endl
+ << seq.subseq(left, right-left+1) << std::endl;
return s.str();
}
};
+ size_t base_pairs_copied = copySelectedTracks(result, AsFasta::formatter);
+ // I wish there was some way to use for_each and bind here
+ for (list<string>::iterator result_i = result.begin();
+ result_i != result.end();
+ ++result_i)
+ {
+ copy_buffer.append(*result_i);
+ }
+ return base_pairs_copied;
+}
- copySelectedTracks(copy_buffer, AsString::formatter);
+//! copy sequence from selected tracks as new sequences
+size_t GlSeqBrowser::copySelectedTracksAsSequences(std::list<Sequence>& result)
+{
+ struct AsSequence {
+ static Sequence formatter(const Sequence& seq,
+ int left,
+ int right)
+ {
+ return seq.subseq(left, right-left+1);
+ }
+ };
+ return copySelectedTracks(result, AsSequence::formatter);
}
-//! copy sequence from selected tracks as FASTA sequences
-void GlSeqBrowser::copySelectedTracksAsFasta(std::string& copy_buffer)
+size_t GlSeqBrowser::copySelectedTracksAsSeqLocation(
+ std::list<SequenceLocation>& result)
{
- struct AsFasta {
- static string formatter(const Sequence& seq, int left, int right)
+ struct AsSeqLocation {
+ static SequenceLocation formatter(const Sequence& seq,
+ int left,
+ int right)
+ {
+ return SequenceLocation(seq, left, right);
+ }
+ };
+ return copySelectedTracks(result, AsSeqLocation::formatter);
+}
+
+//! copy sequence from selected tracks as plain sequences
+size_t GlSeqBrowser::copySelectedTracksAsString(std::string& copy_buffer)
+{
+ std::list<string> result;
+ struct AsString {
+ static string formatter(const Sequence& seq,
+ int left,
+ int right)
{
stringstream s;
- s << ">" << seq.get_header() << std::endl
- << seq.subseq(left, right-left+1) << std::endl;
+ s << seq.subseq(left, right-left+1);
return s.str();
}
};
- copySelectedTracks(copy_buffer, AsFasta::formatter);
+
+ size_t base_pairs_copied = copySelectedTracks(result, AsString::formatter);
+ // I wish there was some way to use for_each and bind here
+ for (list<string>::iterator result_i = result.begin();
+ result_i != result.end();
+ ++result_i)
+ {
+ copy_buffer.append(*result_i);
+ }
+ return base_pairs_copied;
}
void GlSeqBrowser::centerOnPath(const vector<int>& paths)
for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
{
// -15 = shift more to the left
- track_container[track_i].setX((viewport_center-15) - paths[track_i]);
+ track_container[track_i]->setX((viewport_center-15) - paths[track_i]);
}
}
void GlSeqBrowser::update_layout()
{
- typedef std::vector<GlSequence>::iterator glseq_itor_type;
+ typedef std::vector<boost::shared_ptr<GlSequence> >::iterator glseq_itor_type;
float available_height = (float)cur_ortho.top - 2 * (float)border_width;
float max_base_pairs = 0;
size_t track_count = track_container.size();
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();
+ (*seq_i)->setX(0);
+ (*seq_i)->setY(y);
+ if ((*seq_i)->size() > max_base_pairs)
+ max_base_pairs = (*seq_i)->size();
}
} 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();
+ (*seq_i)->setX(0);
+ (*seq_i)->setY(viewport_size.x /2);
+ max_base_pairs = (*seq_i)->size();
} else {
// nothing to do as we're empty
return;
for(size_t track_i = 0; track_i != track_container.size(); ++track_i)
{
glPushName(track_i);
- track_container[track_i].draw(cur_ortho.left, cur_ortho.right);
+ track_container[track_i]->draw(cur_ortho.left, cur_ortho.right);
glPopName();
}
}
void GlSeqBrowser::draw_segments() const
{
glLineWidth(1);
+ glEnable(GL_BLEND);
+ glDepthMask(GL_FALSE);
+ const float zdepth = -1.0;
+ const float min_segment_width = max((float)(1.0), get_pixel_width());
+
// each vector contains path_segment_maps of all the connections
// between this track and the next
path_segment_map_vector::const_iterator psmv_i;
back_inserter(selected));
if (not s.reversed) {
+ // forward
if (selected_paths.size() == 0 or selected.size() > 0) {
- glColor3f(1.0, 0.0, 0.0);
+ glColor4f(1.0, 0.0, 0.0, 1.0);
} else {
- glColor3f(1.0, 0.8, 0.8);
+ glColor4f(1.0, 0.7, 0.7, 0.4);
}
} else {
+ // reverse
if (selected_paths.size() == 0 or selected.size() > 0) {
- glColor3f(0.0, 0.0, 1.0);
+ glColor4f(0.0, 0.0, 1.0, 1.0);
} else {
- glColor3f(0.8, 0.8, 1.0);
+ glColor4f(0.7, 0.7, 1.0, 0.4);
}
- /*
- if (selected_paths.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);
- float seq_start_x = track_container[path_index].x();
- float seq_end_x = track_container[path_index+1].x();
- glVertex3f(s.start.x + seq_start_x, s.start.y, -1);
- glVertex3f(s.end.x + seq_end_x , s.end.y, -1);
- glEnd();
+ float seq_start_x = s.start.x
+ + track_container[path_index]->x();
+ float seq_end_x = s.end.x
+ + track_container[path_index+1]->x();
+ if (s.length <= min_segment_width) {
+ // use lines for elements of length <=1 or < 1 pixel.
+ // and try to center the line
+ const float offset = s.length * 0.5;
+ glBegin(GL_LINES);
+ glVertex3f(seq_start_x+offset, s.start.y, -1);
+ glVertex3f(seq_end_x +offset, s.end.y, -1);
+ glEnd();
+ } else {
+ // otherwise use quads
+ // compute length
+ float seq_start_x_length = s.start.x
+ + s.length
+ + track_container[path_index]->x();
+ float seq_end_x_length = s.end.x
+ + s.length
+ + track_container[path_index+1]->x();
+ glBegin(GL_QUADS);
+ glVertex3f(seq_start_x, s.start.y, zdepth);
+ glVertex3f(seq_end_x, s.end.y, zdepth);
+ glVertex3f(seq_end_x_length, s.end.y, zdepth);
+ glVertex3f(seq_start_x_length, s.start.y, zdepth);
+ glEnd();
+ }
// clear the names
glPopName(); glPopName(); glPopName();
}
}
+ glDepthMask(GL_TRUE);
+ glDisable(GL_BLEND);
}