# include  "tools/cabana/chart/sparkline.h" 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <algorithm> 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								# include  <limits> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								# include  <QPainter> 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  Sparkline : : update ( const  cabana : : Signal  * sig ,  CanEventIter  first ,  CanEventIter  last ,  int  range ,  QSize  size )  { 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( first  = =  last  | |  size . isEmpty ( ) )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pixmap  =  QPixmap ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    return ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  points_ . clear ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  min_val  =  std : : numeric_limits < double > : : max ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  max_val  =  std : : numeric_limits < double > : : lowest ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  points_ . reserve ( std : : distance ( first ,  last ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  uint64_t  start_time  =  ( * first ) - > mono_time ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  double  value  =  0.0 ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  for  ( auto  it  =  first ;  it  ! =  last ;  + + it )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( sig - > getValue ( ( * it ) - > dat ,  ( * it ) - > size ,  & value ) )  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								      min_val  =  std : : min ( min_val ,  value ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      max_val  =  std : : max ( max_val ,  value ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      points_ . emplace_back ( ( ( * it ) - > mono_time  -  start_time )  /  1e9 ,  value ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  if  ( points_ . empty ( ) )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pixmap  =  QPixmap ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    return ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  freq_  =  points_ . size ( )  /  std : : max ( points_ . back ( ) . x ( )  -  points_ . front ( ) . x ( ) ,  1.0 ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  render ( sig - > color ,  range ,  size ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								} 
 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								void  Sparkline : : render ( const  QColor  & color ,  int  range ,  QSize  size )  { 
 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // Adjust for flat lines
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  bool  is_flat_line  =  min_val  = =  max_val ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( is_flat_line )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    min_val  - =  1.0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    max_val  + =  1.0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // Calculate scaling
   
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  const  double  xscale  =  ( size . width ( )  -  1 )  /  ( double ) range ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  const  double  yscale  =  ( size . height ( )  -  3 )  /  ( max_val  -  min_val ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  bool  draw_individual_points  =  ( points_ . back ( ) . x ( )  *  xscale  /  points_ . size ( ) )  >  8.0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  // Transform or downsample points
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  render_points_ . reserve ( points_ . size ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  render_points_ . clear ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( draw_individual_points )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( const  auto  & p  :  points_ )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      render_points_ . emplace_back ( p . x ( )  *  xscale ,  1.0  +  ( max_val  -  p . y ( ) )  *  yscale ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  }  else  if  ( is_flat_line )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    double  y  =  size . height ( )  /  2.0 ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    render_points_ . emplace_back ( 0.0 ,  y ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    render_points_ . emplace_back ( points_ . back ( ) . x ( )  *  xscale ,  y ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  }  else  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    double  prev_y  =  points_ . front ( ) . y ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    render_points_ . emplace_back ( points_ . front ( ) . x ( )  *  xscale ,  1.0  +  ( max_val  -  prev_y )  *  yscale ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    bool  in_flat  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    for  ( size_t  i  =  1 ;  i  <  points_ . size ( ) ;  + + i )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      const  auto  & p  =  points_ [ i ] ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      double  y  =  p . y ( ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      if  ( std : : abs ( y  -  prev_y )  <  1e-6 )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        in_flat  =  true ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      }  else  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        if  ( in_flat )  render_points_ . emplace_back ( points_ [ i  -  1 ] . x ( )  *  xscale ,  1.0  +  ( max_val  -  prev_y )  *  yscale ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        render_points_ . emplace_back ( p . x ( )  *  xscale ,  1.0  +  ( max_val  -  y )  *  yscale ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								        in_flat  =  false ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								      prev_y  =  y ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    if  ( in_flat )  render_points_ . emplace_back ( points_ . back ( ) . x ( )  *  xscale ,  1.0  +  ( max_val  -  prev_y )  *  yscale ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  // Render to pixmap
   
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  qreal  dpr  =  qApp - > devicePixelRatio ( ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  const  QSize  pixmap_size  =  size  *  dpr ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  if  ( pixmap . size ( )  ! =  pixmap_size )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    pixmap  =  QPixmap ( pixmap_size ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  pixmap . setDevicePixelRatio ( dpr ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  pixmap . fill ( Qt : : transparent ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  QPainter  painter ( & pixmap ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  painter . setRenderHint ( QPainter : : Antialiasing ,  render_points_ . size ( )  < =  500 ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  painter . setPen ( color ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  painter . drawPolyline ( render_points_ . data ( ) ,  render_points_ . size ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								
							 
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  painter . setPen ( QPen ( color ,  3 ) ) ; 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								  if  ( draw_individual_points )  { 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								    painter . drawPoints ( render_points_ . data ( ) ,  render_points_ . size ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  }  else  { 
  
						 
					
						
							
								
							 
							
								
									
										 
								
							 
							
								 
							
							
								    painter . drawPoint ( render_points_ . back ( ) ) ; 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								  } 
  
						 
					
						
							
								
							 
							
								
							 
							
								 
							
							
								}