/** \brief Draw line. \param cr is a cairo context \param values that shall be drawn \param max max value on the y-axis \param start is the first value of an interval \param end is the last value of an interval Draws a line based on the values in the interval [start, end]. The line is scaled automatically on the y-axis and x-axis. The resolution of the line is also scaled automatically. The number of values taken into account never exceeds the number of points on x-axis of the cairo context. Therefore the line is drawn in constant time. */ void Graph::draw_line( const Cairo::RefPtr<Cairo::Context> &cr, TValues &values, TValue max, size_t start, size_t end) { assert(start <= end); assert(start >= 0); int w = get_width(); int h = get_height(); int step; float scale_factor_w; float scale_factor_h; unsigned long counter = 0; // size_t interval_size = end - start; step = (end - start) / w + 1; assert(step > 0); scale_factor_w = (float) w / (float) (end - start - 1); //interval_size; scale_factor_h = (float) h / (float) find_max(values, start, end); //(float) max; if (values.size()) { cr->move_to(0, h - values[start] * scale_factor_h); } for (size_t i = step * (start / step) + step; i < end; i += step) { counter++; if(i < values.size()) { cr->line_to(counter * scale_factor_w * step, h - values[i] * scale_factor_h); } } if (values.size()) { cr->move_to(end * scale_factor_w * step, h - values[start] * scale_factor_h); } }
/** \brief Find max value in a collection of data. \param values are a collection of data \param start is the first value of an interval \param end is the last value of an interval \return maximum value Finds max value in a collection of data in an interval [start, end] */ TValue Graph::find_max(TValues &values, TValue start, TValue e) { #if DEBUG assert(start <= e); #endif TValue end = e; if (end > values.size()) { end = values.size(); } #if DEBUG assert(end <= values.size()); #endif TValue max = 0; for (TValue i = start; i < end; i++) { if (i >= 0) { if (max < values[i]) { max = values[i]; } } } return max; }
// ========================================================================= void CWiggleReader::xPreprocessValues(SWiggleStat& stat) // ========================================================================= { bool sorted = true; size_t size = m_Values.size(); if ( size ) { stat.SetFirstSpan(m_Values[0].m_Span); stat.SetFirstValue(m_Values[0].m_Value); for ( size_t i = 1; i < size; ++i ) { stat.AddSpan(m_Values[i].m_Span); stat.AddValue(m_Values[i].m_Value); if ( sorted ) { if ( m_Values[i].m_Pos < m_Values[i-1].m_Pos ) { sorted = false; } if ( m_Values[i].m_Pos != m_Values[i-1].GetEnd() ) { stat.m_HaveGaps = true; } } } } if ( !sorted ) { sort(m_Values.begin(), m_Values.end()); stat.m_HaveGaps = false; for ( size_t i = 1; i < size; ++i ) { if ( m_Values[i].m_Pos != m_Values[i-1].GetEnd() ) { stat.m_HaveGaps = true; break; } } } if ( (m_iFlags & fAsGraph) && stat.m_HaveGaps ) { stat.AddValue(m_GapValue); } const int range = 255; if ( stat.m_Max > stat.m_Min && (!m_KeepInteger || !stat.m_IntValues || stat.m_Max-stat.m_Min > range) ) { stat.m_Step = (stat.m_Max-stat.m_Min)/range; stat.m_StepMul = 1/stat.m_Step; } if ( !(m_iFlags & fAsGraph) && (m_iFlags & fJoinSame) && size ) { TValues nv; nv.reserve(size); nv.push_back(m_Values[0]); for ( size_t i = 1; i < size; ++i ) { if ( m_Values[i].m_Pos == nv.back().GetEnd() && m_Values[i].m_Value == nv.back().m_Value ) { nv.back().m_Span += m_Values[i].m_Span; } else { nv.push_back(m_Values[i]); } } if ( nv.size() != size ) { double s = xEstimateSize(size, stat.m_FixedSpan); double ns = xEstimateSize(nv.size(), false); if ( ns < s*.75 ) { m_Values.swap(nv); size = m_Values.size(); LOG_POST("Joined size: "<<size); stat.m_FixedSpan = false; } } } if ( (m_iFlags & fAsGraph) && !stat.m_FixedSpan ) { stat.m_Span = 1; stat.m_FixedSpan = true; } }