trace_graph.cpp
上传用户:yhdzpy8989
上传日期:2007-06-13
资源大小:13604k
文件大小:34k
源码类别:

生物技术

开发平台:

C/C++

  1. /*
  2.  * ===========================================================================
  3.  * PRODUCTION $Log: trace_graph.cpp,v $
  4.  * PRODUCTION Revision 1000.1  2004/06/01 21:07:29  gouriano
  5.  * PRODUCTION PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  6.  * PRODUCTION
  7.  * ===========================================================================
  8.  */
  9. /*  $Id: trace_graph.cpp,v 1000.1 2004/06/01 21:07:29 gouriano Exp $
  10.  * ===========================================================================
  11.  *
  12.  *                            PUBLIC DOMAIN NOTICE
  13.  *               National Center for Biotechnology Information
  14.  *
  15.  *  This software/database is a 'United States Government Work' under the
  16.  *  terms of the United States Copyright Act.  It was written as part of
  17.  *  the author's official duties as a United States Government employee and
  18.  *  thus cannot be copyrighted.  This software/database is freely available
  19.  *  to the public for use. The National Library of Medicine and the U.S.
  20.  *  Government have not placed any restriction on its use or reproduction.
  21.  *
  22.  *  Although all reasonable efforts have been taken to ensure the accuracy
  23.  *  and reliability of the software and data, the NLM and the U.S.
  24.  *  Government do not and cannot warrant the performance or results that
  25.  *  may be obtained by using this software or data. The NLM and the U.S.
  26.  *  Government disclaim all warranties, express or implied, including
  27.  *  warranties of performance, merchantability or fitness for any particular
  28.  *  purpose.
  29.  *
  30.  *  Please cite the author in any work or product based on this material.
  31.  *
  32.  * ===========================================================================
  33.  *
  34.  * Authors:  Andrey Yazhuk
  35.  *
  36.  * File Description:
  37.  *
  38.  */
  39. #include <ncbi_pch.hpp>
  40. #include <corelib/ncbistd.hpp>
  41. #include <gui/widgets/aln_multiple/trace_graph.hpp>
  42. #include <gui/opengl/glhelpers.hpp>
  43. #include <gui/types.hpp>
  44. #include <math.h>
  45. BEGIN_NCBI_SCOPE
  46. CTraceGraphProperties::CTraceGraphProperties()
  47. :   m_SignalStyle(eCurve),
  48.     m_ConfGraphState(eExpanded),
  49.     m_SignalGraphState(eExpanded),
  50.     m_bReverseColors(true)
  51. {
  52. }
  53. CTraceGraphProperties&  
  54.     CTraceGraphProperties::operator=(const CTraceGraphProperties& orig)
  55. {
  56.     m_SignalStyle = orig.m_SignalStyle;
  57.     m_ConfGraphState = orig.m_ConfGraphState;
  58.     m_SignalGraphState = orig.m_SignalGraphState;
  59.     return *this;
  60. }
  61. ////////////////////////////////////////////////////////////////////////////////
  62. /// CTraceGraph
  63. const static int kGradColors = 32;
  64. CTraceGraph::CTraceGraph(const CBioseq_Handle& handle, bool b_neg_strand)
  65. :   m_DataProxy(handle, b_neg_strand),
  66.     m_pData(NULL)
  67. {
  68. }
  69. CTraceGraph::~CTraceGraph()
  70. {
  71.     Destroy();
  72. }
  73. bool    CTraceGraph::HasData() const
  74. {
  75.     return m_DataProxy.HasData();
  76. }
  77. bool    CTraceGraph::IsCreated() const
  78. {
  79.     return (m_pData != NULL);
  80. }
  81. bool    CTraceGraph::Create()
  82. {
  83.     m_pData = m_DataProxy.LoadData();
  84.     if(m_pData) {
  85.         SetConfGraphState(CTraceGraphProperties::eCollapsed);
  86.     
  87.         bool b_ch = m_pData->GetSamplesCount() > 0;
  88.         SetSignalGraphState(b_ch    ? CTraceGraphProperties::eExpanded 
  89.                                     : CTraceGraphProperties::eHidden);
  90.         
  91.         m_vSignalColors.resize(4 * kGradColors);
  92.         double k = 1.0 / kGradColors;
  93.     
  94.         for( int j = 0; j < kGradColors; j++ )  {
  95.             float v = 1.0f - k * j;
  96.             m_vSignalColors[j] = CGlColor(1.0f, v, v); //red
  97.             m_vSignalColors[kGradColors + j] = CGlColor(v, 1.0f, v); //green
  98.             m_vSignalColors[2 * kGradColors + j] = CGlColor(v, v, 1.0f); //blue
  99.             m_vSignalColors[3 * kGradColors + j] = CGlColor(0.5f * (1 + v), v, 0.5f * (1 + v)); //purple        
  100.         }
  101.         m_pData->CalculateMax();
  102.         return true;
  103.     } else return false;
  104. }
  105. void    CTraceGraph::Destroy()
  106. {
  107.     if(m_pData) {
  108.         delete m_pData;
  109.         m_pData = NULL;
  110.         m_vSignalColors.clear();
  111.     }
  112. }
  113. const IAlnRowGraphProperties*     CTraceGraph::GetProperties() const
  114. {
  115.     return &m_Props;
  116. }
  117. void    CTraceGraph::SetProperties(IAlnRowGraphProperties* props)
  118. {
  119.     CTraceGraphProperties* trace_props = 
  120.         dynamic_cast<CTraceGraphProperties*>(props);
  121.     if(trace_props) {
  122.         m_Props = *trace_props;
  123.     }
  124. }
  125. void    CTraceGraph::SetConfGraphState(EGraphState state)
  126. {
  127.     m_Props.m_ConfGraphState = state;
  128. }
  129. void    CTraceGraph::SetSignalGraphState(EGraphState state)
  130. {
  131.     m_Props.m_SignalGraphState = state;
  132. }
  133. // vertical spacing between graph area border and graph
  134. static const int kGraphOffsetY = 1;
  135. static const int kConfGraphPrefH = 24;
  136. static const int kSignalGraphPrefH = 40;
  137. static const int kCollapsedGraphH = 11;
  138. int     CTraceGraph::GetPreferredHeight()    const
  139. {
  140.     int h = x_GetConfGraphH();
  141.     h += x_GetSignalGraphH();
  142.     h += 2;    
  143.     return h;
  144. }
  145. int     CTraceGraph::x_GetConfGraphH() const
  146. {
  147.     switch(m_Props.m_ConfGraphState)    {
  148.     case CTraceGraphProperties::eCollapsed: return kCollapsedGraphH; 
  149.     case CTraceGraphProperties::eExpanded: return kConfGraphPrefH;
  150.     case CTraceGraphProperties::eHidden: return 0;
  151.     }
  152.     return 0;
  153. }
  154. int     CTraceGraph::x_GetSignalGraphH() const
  155. {
  156.     switch(m_Props.m_SignalGraphState)    {
  157.     case CTraceGraphProperties::eCollapsed: return kCollapsedGraphH; 
  158.     case CTraceGraphProperties::eExpanded: return kSignalGraphPrefH;
  159.     case CTraceGraphProperties::eHidden: return 0;
  160.     }    
  161.     return 0;
  162. }
  163. // renders both Confidence graph and Chromatograms
  164. void    CTraceGraph::Render(CGlPane& pane, int y, int h, const TChunkVec& chunks)
  165. {
  166.     CGlAttrGuard AttrGuard(GL_ENABLE_BIT  | GL_COLOR_BUFFER_BIT | GL_HINT_BIT 
  167.                             | GL_LINE_SMOOTH | GL_POLYGON_MODE | GL_LINE_BIT);
  168.          
  169.     int conf_h = x_GetConfGraphH();
  170.     int sig_h = x_GetSignalGraphH();
  171.     int top_y = y;
  172.     
  173.     pane.OpenOrtho();
  174.     x_RenderContour(pane, top_y, sig_h, conf_h + sig_h, chunks);  // render background
  175.         
  176.     if(m_Props.m_SignalGraphState == CTraceGraphProperties::eExpanded)    {
  177.         if(pane.GetScaleX() < 1.0)   { // render signal graph
  178.             if(m_Props.m_SignalStyle == CTraceGraphProperties::eCurve)   { // render curves
  179.                 glEnable(GL_BLEND);
  180.                 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
  181.     
  182.                 glEnable(GL_LINE_SMOOTH);
  183.                 glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
  184.                 glLineWidth(0.5);
  185.                 x_RenderSignalGraph(pane, top_y, sig_h, chunks);
  186.             } else {            // render intensity bands
  187.                 pane.Close();
  188.                 pane.OpenPixels();
  189.                 glDisable(GL_BLEND);
  190.                 glDisable(GL_LINE_SMOOTH);
  191.                 glLineWidth(1.0);
  192.                 x_RenderIntensityGraphs(pane, top_y, sig_h, chunks);                            
  193.             
  194.                 pane.Close();
  195.                 pane.OpenOrtho();
  196.             }        
  197.         }
  198.         top_y += sig_h;
  199.     }
  200.         
  201.     if(m_Props.m_ConfGraphState == CTraceGraphProperties::eExpanded)   {
  202.         // render confidence graph
  203.         x_RenderConfGraph(pane, top_y, conf_h, chunks);        
  204.     }
  205.     
  206.     pane.Close();    
  207. }
  208. // Functor for coordinate translation align <->seq
  209. struct SChunkTranslator
  210. {
  211. public:
  212.     SChunkTranslator()
  213.     : m_pSeqRange(NULL), m_pAlnRange(NULL), m_bNegative(false)
  214.     {
  215.     }
  216.     
  217.     void Init(const TSignedSeqRange& seq_range, 
  218.               const TSignedSeqRange& aln_range, bool negative)
  219.     {        
  220.         m_pSeqRange = &seq_range;
  221.         m_pAlnRange = &aln_range;
  222.         m_bNegative = negative;
  223.         _ASSERT(m_pSeqRange->GetLength() == m_pAlnRange->GetLength());    
  224.     }
  225.     inline TSignedSeqPos GetAlnPosFromSeqPos(TSignedSeqPos seq_pos)
  226.     {
  227.         _ASSERT(m_pSeqRange  && m_pAlnRange);
  228.         TSignedSeqPos seq_off = seq_pos - m_pSeqRange->GetFrom();
  229.         if(m_bNegative)    {
  230.           return m_pAlnRange->GetTo() - seq_off;
  231.         } else return seq_off + m_pAlnRange->GetFrom();
  232.     }
  233.     inline double GetAlnPosFromSeqPos(double seq_pos)
  234.     {
  235.         _ASSERT(m_pSeqRange  && m_pAlnRange);
  236.         double seq_off = seq_pos - m_pSeqRange->GetFrom();
  237.         if(m_bNegative)    {
  238.           return m_pAlnRange->GetTo() - seq_off;
  239.         } else return seq_off + m_pAlnRange->GetFrom();
  240.     }
  241.     inline TSignedSeqPos GetSeqPosFromAlnPos(TSignedSeqPos aln_pos)
  242.     {
  243.         _ASSERT(m_pSeqRange  && m_pAlnRange);
  244.         TSignedSeqPos aln_off = aln_pos - m_pAlnRange->GetFrom();
  245.         if(m_bNegative)    {
  246.           return m_pSeqRange->GetTo() - aln_off;
  247.         } else return aln_off + m_pSeqRange->GetFrom();
  248.     }
  249.     inline double GetSeqPosFromAlnPos(double aln_pos)
  250.     {
  251.         _ASSERT(m_pSeqRange  && m_pAlnRange);
  252.         double aln_off = aln_pos - m_pAlnRange->GetFrom();
  253.         if(m_bNegative)    {
  254.           return m_pSeqRange->GetTo() - aln_off;
  255.         } else return aln_off + m_pSeqRange->GetFrom();
  256.     }
  257. protected:
  258.     const TSignedSeqRange* m_pSeqRange;
  259.     const TSignedSeqRange* m_pAlnRange;
  260.     bool    m_bNegative;
  261. };
  262. void    CTraceGraph::x_RenderContour(CGlPane& pane, int y, int top_h, int total_h,
  263.                                       const TChunkVec& chunks)
  264. {
  265.     glDisable(GL_BLEND);
  266.     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  267.     glColor3d(0.9, 0.9, 0.9);
  268.     
  269.     TModelUnit offset_x = pane.GetOffsetX();
  270.     TModelUnit y1 = y;
  271.     TModelUnit y2 = y + top_h - 1;
  272.     TModelUnit y3 = y + top_h + 1;
  273.     TModelUnit y4 = y + total_h - 1;
  274.     TSignedSeqRange gr_range = TSignedSeqRange(m_pData->GetSeqFrom(), m_pData->GetSeqTo());
  275.     SChunkTranslator    trans;
  276.     
  277.     for( int i = 0; i < chunks->size(); i++  )   { // iterate by chunks
  278.         CConstRef<CAlnMap::CAlnChunk> ch = (*chunks)[i];
  279.         
  280.         if(ch->GetType() & CAlnMap::fSeq) { // if chunk aligned
  281.             TSignedSeqRange ch_range = ch->GetRange();  
  282.             const TSignedSeqRange& ch_aln_range = ch->GetAlnRange();
  283.             trans.Init(ch_range, ch_aln_range, m_pData->IsNegative());
  284.             
  285.             // intersect 
  286.             ch_range.IntersectWith(gr_range);
  287.             
  288.             if(ch_range.NotEmpty())   {           
  289.                 
  290.                 double x1 = trans.GetAlnPosFromSeqPos(ch_range.GetFrom()) - offset_x;
  291.                 double x2 = trans.GetAlnPosFromSeqPos(ch_range.GetTo()) - offset_x;
  292.                 if(x1 > x2) {
  293.                     swap(x1, x2);
  294.                 }
  295.                 x2 += 1.0;
  296.                 glRectd(x1, y1, x2, y2);
  297.                 glRectd(x1, y3, x2, y4);
  298.             }
  299.         }
  300.     }
  301. }
  302. const static float kEps = 0.000001f; // precision for float point comparisions
  303. // renders confidence graph
  304. void    CTraceGraph::x_RenderConfGraph(CGlPane& pane, int y, int h, 
  305.                               const TChunkVec& chunks)
  306. {
  307.     const TVPRect& rc_vp = pane.GetViewport();
  308.     const TModelRect rc_vis = pane.GetVisibleRect();
  309.     glDisable(GL_BLEND);   
  310.     glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
  311.     
  312.     TModelUnit amp  = ((TModelUnit) h - 2 * kGraphOffsetY -1)
  313.                         / m_pData->GetMaxConfidence();
  314.     TModelUnit base_y = y + kGraphOffsetY;
  315.     TModelUnit scale_x = pane.GetScaleX();
  316.     TSignedSeqPos gr_from = m_pData->GetSeqFrom();
  317.     TSignedSeqPos gr_to = m_pData->GetSeqTo();
  318.     
  319.     SChunkTranslator trans;
  320.     bool b_average = (scale_x > 0.3);
  321.     if(b_average)    {
  322.         pane.Close();
  323.         pane.OpenPixels();
  324.         //calculate visible range in seq coords
  325.         TVPUnit range_pix_start = rc_vp.Left();
  326.         TVPUnit range_pix_end = rc_vp.Right();
  327.         
  328.         TModelUnit  left = rc_vis.Left();
  329.         TModelUnit  scale_x = pane.GetScaleX();
  330.         TModelUnit  top_y = rc_vp.Bottom() - (y + kGraphOffsetY);
  331.         glBegin(GL_LINES);
  332.         int i_prev_chunk = -1, i_chunk = 0, n_chunks = chunks->size();
  333.         CConstRef<CAlnMap::CAlnChunk> ch;
  334.         CAlnMap::TSegTypeFlags type;
  335.         TModelUnit ch_pix_end;
  336.         TModelUnit pos_pix_left, pos_pix_right;
  337.         TSignedSeqPos from = -1, to = -2;
  338.         TSignedSeqPos pos = gr_from, pos_inc = 1;
  339.         double v = 0, v_min = 0, v_max = 0;
  340.             
  341.         for( int pix = range_pix_start; 
  342.              pix <= range_pix_end  &&  i_chunk < n_chunks  &&  pos <= gr_to; )   { // iterate by pixels
  343.             bool b_first = true;
  344.             // if chunks ends before pixel 
  345.             if(i_prev_chunk != i_chunk) {
  346.                 // advance chunk
  347.                 ch = (*chunks)[i_chunk];
  348.                 type = ch->GetType();
  349.                 if(type & CAlnMap::fSeq) {             
  350.                     const TSignedSeqRange& ch_range = ch->GetRange();  
  351.                     const TSignedSeqRange& ch_aln_range = ch->GetAlnRange();
  352.                 
  353.                     trans.Init(ch_range, ch_aln_range, m_pData->IsNegative());
  354.                 
  355.                     // calculate intersection of chunk in seq_coords with graph range
  356.                     from = max(ch_range.GetFrom(), gr_from);
  357.                     to = min(ch_range.GetTo(), gr_to);
  358.                 
  359.                     // clip with visible align range (expanding integer clip)
  360.                     TSignedSeqPos vis_from = trans.GetSeqPosFromAlnPos((TSignedSeqPos) floor(rc_vis.Left()));
  361.                     TSignedSeqPos vis_to = trans.GetSeqPosFromAlnPos((TSignedSeqPos) ceil(rc_vis.Right()));
  362.                     if(vis_to < vis_from)   {
  363.                         _ASSERT(m_pData->IsNegative());
  364.                         swap(vis_from, vis_to);
  365.                     }
  366.                     from = max(from, vis_from);
  367.                     to = min(to, vis_to);
  368.                     if(m_pData->IsNegative()) {
  369.                         ch_pix_end = range_pix_start + (trans.GetAlnPosFromSeqPos(from) + 1 - left) / scale_x;
  370.                         pos = to;
  371.                         pos_inc = -1;
  372.                     } else {
  373.                         ch_pix_end = range_pix_start + (trans.GetAlnPosFromSeqPos(to) + 1 - left) / scale_x;
  374.                         pos = from;
  375.                         pos_inc = 1;
  376.                     }
  377.                 }
  378.                 i_prev_chunk = i_chunk;
  379.             }
  380.             
  381.             if(type & CAlnMap::fSeq) {         
  382.                 TSignedSeqPos aln_pos = trans.GetAlnPosFromSeqPos(pos);
  383.                 pos_pix_left = range_pix_start + (aln_pos - left) / scale_x;
  384.                 pos_pix_right = pos_pix_left + 1 / scale_x;
  385.                 
  386.                 pos_pix_left = max((TModelUnit) pix, pos_pix_left);                
  387.                 _ASSERT(pos_pix_left >= pix);
  388.                 while(pos >= from  &&  pos <= to  &&  pos_pix_left < pix + 1)   {                
  389.                     // calculate overlap with pixel and integrate
  390.                     double v = amp * m_pData->GetConfidence(pos);
  391.                     
  392.                     v_min = b_first ? v : min(v_min, v);
  393.                     v_max = b_first ? v : max(v_max, v);
  394.                     b_first = false;
  395.                     
  396.                     if(pos_pix_right < pix +1)  {
  397.                         pos +=pos_inc; // advance to next pos
  398.                         aln_pos = trans.GetAlnPosFromSeqPos(pos);
  399.                         pos_pix_left = range_pix_start + (aln_pos - left) / scale_x;
  400.                         pos_pix_right = pos_pix_left + 1 / scale_x;
  401.                     } else break;                    
  402.                 }
  403.             } 
  404.             if(ch_pix_end < pix + 1) {
  405.                 i_chunk++;
  406.             } else  {           
  407.                 if(type & CAlnMap::fSeq) { 
  408.                     glColor3d(0.0f, 0.5f, 0.0f);                
  409.                     glVertex2d(pix, top_y);
  410.                     glVertex2d(pix, top_y - v_min);
  411.                     glColor3d(0.0f, 0.75f, 0.25f);
  412.                     glVertex2d(pix, top_y - v_min);
  413.                     glVertex2d(pix, top_y - v_max);
  414.                 
  415.                 }
  416.                 pix++;
  417.                 v = v_min = v_max = 0;
  418.             }
  419.         }    
  420.         glEnd();
  421.     } else { // render without averaging
  422.         _ASSERT(pane.GetProjMode() == CGlPane::eOrtho);
  423.         
  424.         TModelUnit offset_x = pane.GetOffsetX();
  425.         glColor3d(0.0f, 0.5f, 0.0f); //###
  426.         for( int i = 0; i < chunks->size(); i++  )   { // iterate by chunks
  427.             CConstRef<CAlnMap::CAlnChunk> ch = (*chunks)[i];
  428.             CAlnMap::TSegTypeFlags type = ch->GetType();
  429.             if(type & CAlnMap::fSeq) { // if chunk aligned
  430.                 const TSignedSeqRange& ch_range = ch->GetRange();  
  431.                 const TSignedSeqRange& ch_aln_range = ch->GetAlnRange();
  432.                 trans.Init(ch_range, ch_aln_range, m_pData->IsNegative());
  433.                 TSignedSeqPos from = max(gr_from, ch_range.GetFrom());
  434.                 TSignedSeqPos to = min(gr_to, ch_range.GetTo());
  435.            
  436.                 for( TSignedSeqPos pos = from; pos <= to; pos ++ ) {
  437.                     double v = m_pData->GetConfidence(pos);
  438.                     v *= amp;
  439.                     TSignedSeqPos aln_pos = trans.GetAlnPosFromSeqPos(pos);
  440.                     double x = aln_pos - offset_x;
  441.                     glRectd(x , base_y, x + 1.0, base_y + v);
  442.                 }
  443.             }
  444.         }
  445.     }
  446. }
  447. const static int kIntBandSpace = 1;
  448. void    CTraceGraph::x_RenderSignalGraph(CGlPane& pane, int y, int h, 
  449.                                 const TChunkVec& chunks)
  450. {
  451.     CTraceData::TSignalValue MaxSignal = 0;
  452.     for( int ch = CTraceData::eA; ch <= CTraceData::eG; ch++ )   {
  453.         MaxSignal = max(MaxSignal, m_pData->GetMax( (CTraceData::EChannel) ch));
  454.     }
  455.     TModelUnit amp  = ((TModelUnit) (h - 2 * kGraphOffsetY)) / MaxSignal; 
  456.     int bottom_y = y + (h - 1) - kGraphOffsetY;
  457.     
  458.     for( int i_ch = 0; i_ch < 4; i_ch++ )   {   // for every channel (i_ch - channel index)
  459.         int ch_index = (m_Props.m_bReverseColors  &&  m_pData->IsNegative()) ? (i_ch ^ 2) : i_ch;
  460.         int ch = CTraceData::eA + ch_index;
  461.     
  462.         const CTraceData::TPositions& positions = m_pData->GetPositions();
  463.         
  464.         CTraceData::EChannel channel = (CTraceData::EChannel) ch;
  465.         const CTraceData::TValues& values = m_pData->GetValues(channel);
  466.         glColorC(m_vSignalColors[kGradColors * (i_ch + 1) -1]);
  467.         glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
  468.         _ASSERT(m_Props.m_SignalStyle == CTraceGraphProperties::eCurve);
  469.         for( int i = 0; i < chunks->size(); i++  )   {
  470.             CConstRef<CAlnMap::CAlnChunk> ch = (*chunks)[i];
  471.             CAlnMap::TSegTypeFlags type = ch->GetType();
  472.             if(type & CAlnMap::fSeq) {
  473.                 x_RenderCurveChunk(pane, ch, positions, values, bottom_y, h, (int) amp);            
  474.             }
  475.         }
  476.     }
  477. }
  478. // Renders chromatogram corresponding to given chunk of sequence.
  479. // This function renders data as a curve for a single channel specified by "values".
  480. void    CTraceGraph::x_RenderCurveChunk(CGlPane& pane, 
  481.                                           CConstRef<CAlnMap::CAlnChunk> ch, 
  482.                                           const CTraceData::TPositions& positions, 
  483.                                           const CTraceData::TValues& values,
  484.                                           int bottom_y, int h, int amp)
  485. {
  486.     const TModelRect rc_vis = pane.GetVisibleRect();
  487.     const TSignedSeqRange& ch_range = ch->GetRange();  
  488.     const TSignedSeqRange& ch_aln_range = ch->GetAlnRange();
  489.     SChunkTranslator trans;
  490.     bool b_neg = m_pData->IsNegative();
  491.     trans.Init(ch_range, ch_aln_range, m_pData->IsNegative());
  492.     
  493.     // [from, to] - is sequence range for which graph is rendered
  494.     double from = max(m_pData->GetSeqFrom(), ch_range.GetFrom());
  495.     double to = min(m_pData->GetSeqTo(), ch_range.GetTo());
  496.     
  497.     double vis_from = trans.GetSeqPosFromAlnPos(rc_vis.Left());
  498.     double vis_to = trans.GetSeqPosFromAlnPos(rc_vis.Right());
  499.     if(vis_to < vis_from)   {
  500.         _ASSERT(m_pData->IsNegative());
  501.         swap(vis_from, vis_to);
  502.     }
  503.     from = max(from, vis_from);
  504.     to = min(to, vis_to);
  505.     if(from <= to)  {
  506.         int sm_start = x_FindSampleToLeft(from);
  507.         int sm_end = x_FindSampleToRight(to + 1);
  508.         sm_start = max(0, sm_start);
  509.         sm_end = min(sm_end, m_pData->GetSamplesCount() - 1);
  510.    
  511.         if(sm_start <= sm_end)  {
  512.             glBegin(GL_QUAD_STRIP);
  513.             TModelUnit offset_x = pane.GetOffsetX();
  514.          
  515.             // check if start interpolation is needed
  516.             CTraceData::TFloatSeqPos sm_start_seqpos = positions[sm_start];
  517.             if(sm_start_seqpos < from)   {
  518.                 if(sm_start + 1 < sm_end)   {
  519.                     double v1 = values[sm_start];
  520.                     double v2 = values[sm_start + 1];
  521.                     double x1 = sm_start_seqpos;
  522.                     double x2 = positions[sm_start + 1];
  523.                     double v = v1 + ((from - x1) * (v2 - v1) / (x2 - x1));
  524.                     v *= amp;
  525.                     
  526.                     double aln_from = trans.GetAlnPosFromSeqPos(from + (b_neg ? -1 : 0));
  527.                     glVertex2d(aln_from - offset_x, bottom_y - v); 
  528.                     //glVertex2d(aln_from - offset_x, bottom_y);                 
  529.                 }
  530.                 sm_start++;
  531.             }
  532.             // render regular samples
  533.             for( int i_sm = sm_start; i_sm < sm_end; i_sm++  ) {
  534.                 TModelUnit seqpos = positions[i_sm];
  535.                 double v = values[i_sm];
  536.                 v *= amp;
  537.         
  538.                 double aln_pos = trans.GetAlnPosFromSeqPos(seqpos + (b_neg ? -1 : 0));
  539.                 glVertex2d(aln_pos - offset_x, bottom_y - v); 
  540.                 //glVertex2d(aln_pos - offset_x, bottom_y);                 
  541.             }
  542.             // render end point
  543.             if( sm_end - 1 > sm_start) { // interpolate end point
  544.                 double v1 = values[sm_end -1];
  545.                 double v2 = values[sm_end];
  546.                 double x1 = positions[sm_end - 1];
  547.                 double x2 = positions[sm_end];
  548.                 double v = v1 + ((to + 1 - x1) * (v2 - v1) / (x2 - x1));
  549.                 v *= amp;
  550.     
  551.                 double aln_to = trans.GetAlnPosFromSeqPos(to + (b_neg ? 0 : 1));
  552.                 glVertex2d(aln_to - offset_x, bottom_y - v); 
  553.                 //glVertex2d(aln_to - offset_x, bottom_y);  
  554.             } else {
  555.                TModelUnit seqpos = positions[sm_end];
  556.                 double v = values[sm_end];
  557.                 v *= amp;
  558.         
  559.                 double aln_pos = trans.GetAlnPosFromSeqPos(seqpos);
  560.                 glVertex2d(aln_pos - offset_x, bottom_y - v); 
  561.                 //glVertex2d(aln_pos - offset_x, bottom_y);                 
  562.             }
  563.             glEnd();
  564.         }
  565.     }
  566. }
  567. /// Render signals for all channels as gradient-color bands with color intensity
  568. /// proprotional to signal strength.
  569. void    CTraceGraph::x_RenderIntensityGraphs(CGlPane& pane, int y, int h, 
  570.                                              const TChunkVec& chunks)
  571. {   
  572.     //_TRACE("nx_RenderIntensityGraphs");
  573.     const CTraceData::TPositions& positions = m_pData->GetPositions();
  574.     
  575.     const TVPRect& rc_vp = pane.GetViewport();
  576.     const TModelRect rc_vis = pane.GetVisibleRect();
  577.   
  578.     // calculate layout
  579.     int av_h = h - 2 * kGraphOffsetY; // height available for intensity bands
  580.     int band_h = av_h / 4;
  581.     int off = (av_h - 4 * band_h) / 2; // rounding error compensation
  582.     int top_y = rc_vp.Bottom() - (y + kGraphOffsetY + off);
  583.     
  584.     TModelUnit  left = rc_vis.Left();
  585.     TModelUnit  scale_x = pane.GetScaleX();
  586.     TVPUnit range_pix_start = rc_vp.Left();
  587.     TVPUnit range_pix_end = rc_vp.Right();
  588.     SChunkTranslator trans;
  589.     glBegin(GL_LINES);
  590.     
  591.     int i_chunk = 0, n_chunks = chunks->size();            
  592.     CConstRef<CAlnMap::CAlnChunk> chunk;
  593.   
  594.     // iterate by pixels,samples and chunks
  595.     for( int pix = range_pix_start; 
  596.          pix <= range_pix_end  &&  i_chunk < n_chunks;  i_chunk++ )
  597.     {
  598.         _ASSERT(i_chunk >=0  && i_chunk < n_chunks);
  599.         chunk = (*chunks)[i_chunk];            
  600.         if(chunk->GetType() & CAlnMap::fSeq)    { // if chunk is aligned
  601.             //calc samples range by chunk 
  602.             const TSignedSeqRange& ch_range = chunk->GetRange();  
  603.             const TSignedSeqRange& ch_aln_range = chunk->GetAlnRange();
  604.             trans.Init(ch_range, ch_aln_range, m_pData->IsNegative());
  605.             
  606.             // [from, to] - is sequence range for which graph is rendered
  607.             double from = max(m_pData->GetSeqFrom(), ch_range.GetFrom());
  608.             double to = min(m_pData->GetSeqTo(), ch_range.GetTo());
  609.             
  610.             double vis_from = trans.GetSeqPosFromAlnPos(rc_vis.Left());
  611.             double vis_to = trans.GetSeqPosFromAlnPos(rc_vis.Right());
  612.             if(vis_to < vis_from)   {
  613.                 _ASSERT(m_pData->IsNegative());
  614.                 swap(vis_from, vis_to);
  615.             }
  616.             
  617.             from = max(from, vis_from);
  618.             to = min(to, vis_to);
  619.             
  620.             // [sm_start, sm_end] - samples range being rendered
  621.             int sm_start = x_FindSampleToLeft(from);
  622.             int sm_end = x_FindSampleToRight(to + 1);
  623.             sm_start = max(sm_start, 0);
  624.             sm_end = min(sm_end, m_pData->GetSamplesCount() - 1);
  625.             
  626.             // calculate pixels range to render        
  627.             double aln_from = trans.GetAlnPosFromSeqPos(from);
  628.             double aln_to = trans.GetAlnPosFromSeqPos(to);
  629.             if(m_pData->IsNegative())   {
  630.                 swap(aln_from, aln_to);
  631.             }
  632.             aln_to += 1;
  633.             
  634.             TVPUnit pix_start = range_pix_start + (TVPUnit) floor((aln_from - left) / scale_x);
  635.             TVPUnit pix_end = range_pix_start + (TVPUnit) ceil((aln_to - left) / scale_x);                        
  636.             pix_start = max(pix_start, range_pix_start);
  637.             pix_end = min(pix_end, range_pix_end);
  638.             
  639.             int sm_inc = m_pData->IsNegative() ? -1 : +1;
  640.             int band_y = top_y;
  641.             for( int i_ch = 0; i_ch < 4; i_ch++ )   {   // for every channel (i_ch - channel index)
  642.                 int ch_index = (m_Props.m_bReverseColors  &&  m_pData->IsNegative()) ? (i_ch ^ 2) : i_ch;
  643.                 int ch = CTraceData::eA + ch_index;
  644.                     
  645.                 const CTraceData::TValues& values = m_pData->GetValues((CTraceData::EChannel) ch);
  646.                 CTraceData::TSignalValue MaxSignal = m_pData->GetMax((CTraceData::EChannel) ch);
  647.                 double x1, x2, pix_x1, pix_x2;
  648.                 double v1, v2, s, dx, sum, sum_pix_x;
  649.                 int sample = m_pData->IsNegative() ? sm_end : sm_start;                
  650.                 _ASSERT(sample >= 0);
  651.                 for( TVPUnit pix = pix_start; pix <= pix_end;  pix++ )  { // for each pixel
  652.                     // calculate average value for "pix" pixel by integrating values
  653.                     // over the range [pix, pix+1]
  654.                     sum = 0; // integral from values by pix_x
  655.                     sum_pix_x = 0; // length of integrated range
  656.                     x1 = positions[sample];       
  657.                     if(m_pData->IsNegative()) 
  658.                         x1 -= 1.0;
  659.                     pix_x1 = range_pix_start + (trans.GetAlnPosFromSeqPos(x1) - left) / scale_x; 
  660.                     v1 = v2 = values[sample]; //#####
  661.                     if(pix_x1 < pix + 1)    {
  662.                         bool b_next_point = m_pData->IsNegative() ? (sample > sm_start) : (sample < sm_end);
  663.                         if(b_next_point) { // there is second point available
  664.                             x2 = positions[sample + sm_inc];
  665.                             if(m_pData->IsNegative()) 
  666.                                 x2 -= 1.0;
  667.                             pix_x2 = range_pix_start + (trans.GetAlnPosFromSeqPos(x2) - left) / scale_x; 
  668.                             v2 = values[sample + sm_inc];
  669.                         
  670.                             if(pix_x1 < pix)    { // fisrt sample is to the left of this pixel                        
  671.                                 // replace it fake interpolated sample at x = "pix"
  672.                                 v1 += (v2 - v1) * (pix - pix_x1) / (pix_x2 - pix_x1);
  673.                                 pix_x1 = pix;
  674.                             }
  675.                         }    
  676.                         while(b_next_point  &&  pix_x2 <= pix + 1) // while second point is inside pixel
  677.                         {
  678.                             dx = pix_x2 - pix_x1;
  679.                             s = 0.5 * (v1 + v2) * dx;
  680.                             _ASSERT(s >=0  &&  dx >= 0);
  681.                             
  682.                             sum += s;
  683.                             sum_pix_x += dx;
  684.                             sample += sm_inc; // advance, x2 becomes x1
  685.                             pix_x1 = pix_x2;
  686.                             v1 = v2;                        
  687.                         
  688.                             b_next_point = m_pData->IsNegative() ? (sample > sm_start) : (sample < sm_end);
  689.                             if(b_next_point) {
  690.                                 x2 = positions[sample + sm_inc];
  691.                                 if(m_pData->IsNegative()) 
  692.                                     x2 -= 1.0;
  693.                                 pix_x2 = range_pix_start + (trans.GetAlnPosFromSeqPos(x2) - left) / scale_x;
  694.                                 v2 = values[sample + sm_inc];  
  695.                             } else break;
  696.                         }   
  697.                         _ASSERT(pix_x1 <= pix + 1);
  698.                     
  699.                         if(b_next_point  &&  pix_x2 > pix + 1)    { // second point is outside pixel
  700.                             dx = pix + 1 - pix_x1;
  701.                             _ASSERT(dx >= 0);
  702.                             
  703.                             double v = v1 + (v2 - v1) * dx / (pix_x2 - pix_x1);
  704.                             s = 0.5 * (v1 + v) * dx;
  705.                         
  706.                             _ASSERT(s >=0  &&  dx >= 0);
  707.                             sum += s;
  708.                             sum_pix_x += dx;
  709.                         }
  710.                         double av_v = (sum_pix_x) > 0  ? sum / sum_pix_x : 0;
  711.                     
  712.                         // render pixel
  713.                         double norm = (MaxSignal == 0) ? 0 : (av_v / MaxSignal);
  714.                         const CGlColor& col = GetColorByValue(norm, i_ch);
  715.                         glColorC(col);
  716.                         glVertex2d(pix, band_y);
  717.                         glVertex2d(pix, band_y - band_h - 1);
  718.                     } // if(pix < pix + 1)
  719.                 }
  720.                 band_y -= band_h;
  721.             }
  722.         }
  723.     }
  724.     glEnd();
  725. }
  726. // returns gradient color corresponding to normalized [0, 1.0] value "value" 
  727. // for channel specified by "signal" 
  728. const CGlColor&     CTraceGraph::GetColorByValue(double value, int signal) const
  729. {
  730.     _ASSERT(value >= 0  &&  value <= 1.0);
  731.     _ASSERT(signal >= 0  &&  signal <= 3);
  732.     int i = (int) (value * kGradColors);
  733.     i = min(i, kGradColors);
  734.     int index = signal * kGradColors + i;
  735.     return m_vSignalColors[index];
  736. }
  737. /// returns index of rightmost sample having m_SeqPos less then "pos".
  738. /// if "pos" is to the left of the trace range function returns -1,
  739. /// if "pos" is to the right of the trace range functions returns "n_samples"
  740. int CTraceGraph::x_FindSampleToLeft(double pos) const
  741. {
  742.     int n_samples = m_pData->GetSamplesCount();        
  743.     if(pos < m_pData->GetSeqFrom()  || n_samples == 0)  {
  744.         return -1;
  745.     } else if(pos > m_pData->GetSeqTo())   {
  746.         return n_samples;
  747.     } else {
  748.         const CTraceData::TPositions& positions = m_pData->GetPositions();
  749.         double scale = ((double) n_samples) / m_pData->GetSeqLength();
  750.         
  751.         // calculate approximate sample index
  752.         int i = (int) (scale * (pos - m_pData->GetSeqFrom()));
  753.         i = min(i, n_samples - 1);
  754.         i = max(i, 0);
  755.         
  756.         if(positions[i] > pos)  {
  757.             for(  ; i > 0  &&  positions[i] > pos;  i-- )  {          
  758.             }
  759.         } else {
  760.             for(  ; ++i < n_samples  &&  positions[i] < pos;  )  {          
  761.             }
  762.             i--;
  763.         }
  764.         return i;
  765.     }
  766. }
  767. /// returns index of the leftmost sample having m_SeqPos greater than "pos"
  768. /// if "pos" is to the left of the trace range function returns -1,
  769. /// if "pos" is to the right of the trace range functions returns "n_samples"
  770. int CTraceGraph::x_FindSampleToRight(double pos) const
  771. {
  772.     int n_samples = m_pData->GetSamplesCount();        
  773.     if(pos < m_pData->GetSeqFrom()  || n_samples == 0)  {
  774.         return -1;
  775.     } else if(pos > m_pData->GetSeqTo())   {
  776.         return n_samples;
  777.     } else {
  778.         const CTraceData::TPositions& positions = m_pData->GetPositions();        
  779.         double scale = ((double) n_samples) / m_pData->GetSeqLength();
  780.         
  781.         // calculate approximate sample index
  782.         int i = (int) (scale * (pos - m_pData->GetSeqFrom()));
  783.         i = min(i, n_samples - 1);
  784.         i = max(i, 0);
  785.         
  786.         if(positions[i] > pos)  {
  787.             for(  ; i > 0  &&  positions[i] > pos;  i-- ) {          
  788.             }
  789.             i++;
  790.         } else {
  791.             for(  ; ++i < n_samples  &&  positions[i] < pos;  ) {          
  792.             }
  793.         }
  794.         return i;
  795.     }
  796. }
  797. END_NCBI_SCOPE
  798. /*
  799.  * ===========================================================================
  800.  * $Log: trace_graph.cpp,v $
  801.  * Revision 1000.1  2004/06/01 21:07:29  gouriano
  802.  * PRODUCTION: UPGRADED [GCC34_MSVC7] Dev-tree R1.9
  803.  *
  804.  * Revision 1.9  2004/05/21 22:27:52  gorelenk
  805.  * Added PCH ncbi_pch.hpp
  806.  *
  807.  * Revision 1.8  2004/05/14 13:20:51  yazhuk
  808.  * Implemented color reversing for traces on negative strand
  809.  *
  810.  * Revision 1.7  2004/05/10 17:46:35  yazhuk
  811.  * Addressed GCC warnings
  812.  *
  813.  * Revision 1.6  2004/03/29 18:59:47  yazhuk
  814.  * Added support for data loading and Properties management
  815.  *
  816.  * Revision 1.5  2004/03/26 14:59:49  yazhuk
  817.  * Renamed EMode to ESignalStyle; a number of rendering improvements
  818.  *
  819.  * Revision 1.4  2004/03/25 13:05:50  dicuccio
  820.  * Use _TRACE() instead of cout
  821.  *
  822.  * Revision 1.3  2004/03/11 17:50:41  dicuccio
  823.  * Updated typedefs: dropped TDimension, TPosition, TIndex, TColor; use TSeqRange
  824.  * instead of TRange
  825.  *
  826.  * Revision 1.2  2004/03/08 15:38:16  yazhuk
  827.  * Implemented state management expanded/collapsed/hidden
  828.  *
  829.  * Revision 1.1  2004/03/02 15:13:51  yazhuk
  830.  * Initial revision
  831.  *
  832.  * ===========================================================================
  833.  */