@ -69,8 +69,8 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
column_count = settings . chart_column_count ;
column_count = settings . chart_column_count ;
QObject : : connect ( dbc ( ) , & DBCManager : : DBCFileChanged , this , & ChartsWidget : : removeAll ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : DBCFileChanged , this , & ChartsWidget : : removeAll ) ;
QObject : : connect ( can , & CANMessages : : eventsMerged , this , & ChartsWidget : : eventsMerged ) ;
QObject : : connect ( can , & AbstractStream : : eventsMerged , this , & ChartsWidget : : updateState ) ;
QObject : : connect ( can , & CANMessages : : updated , this , & ChartsWidget : : updateState ) ;
QObject : : connect ( can , & AbstractStream : : updated , this , & ChartsWidget : : updateState ) ;
QObject : : connect ( show_all_values_btn , & QAction : : triggered , this , & ChartsWidget : : showAllData ) ;
QObject : : connect ( show_all_values_btn , & QAction : : triggered , this , & ChartsWidget : : showAllData ) ;
QObject : : connect ( remove_all_btn , & QAction : : triggered , this , & ChartsWidget : : removeAll ) ;
QObject : : connect ( remove_all_btn , & QAction : : triggered , this , & ChartsWidget : : removeAll ) ;
QObject : : connect ( reset_zoom_btn , & QAction : : triggered , this , & ChartsWidget : : zoomReset ) ;
QObject : : connect ( reset_zoom_btn , & QAction : : triggered , this , & ChartsWidget : : zoomReset ) ;
@ -83,27 +83,33 @@ ChartsWidget::ChartsWidget(QWidget *parent) : QWidget(parent) {
} ) ;
} ) ;
}
}
void ChartsWidget : : eventsMerged ( ) {
if ( auto events = can - > events ( ) ; events & & ! events - > empty ( ) ) {
event_range . first = ( events - > front ( ) - > mono_time / ( double ) 1e9 ) - can - > routeStartTime ( ) ;
event_range . second = ( events - > back ( ) - > mono_time / ( double ) 1e9 ) - can - > routeStartTime ( ) ;
updateState ( ) ;
}
}
void ChartsWidget : : updateDisplayRange ( ) {
void ChartsWidget : : updateDisplayRange ( ) {
auto prev_range = display_range ;
auto events = can - > events ( ) ;
double current_sec = can - > currentSec ( ) ;
double min_event_sec = ( events - > front ( ) - > mono_time / ( double ) 1e9 ) - can - > routeStartTime ( ) ;
if ( current_sec < display_range . first | | current_sec > = ( display_range . second - 5 ) ) {
double max_event_sec = ( events - > back ( ) - > mono_time / ( double ) 1e9 ) - can - > routeStartTime ( ) ;
// reached the end, or seeked to a timestamp out of range.
const double cur_sec = can - > currentSec ( ) ;
display_range . first = current_sec - 5 ;
if ( ! can - > liveStreaming ( ) ) {
}
auto prev_range = display_range ;
display_range . first = std : : floor ( std : : max ( display_range . first , event_range . first ) * 10.0 ) / 10.0 ;
if ( cur_sec < display_range . first | | cur_sec > = ( display_range . second - 5 ) ) {
display_range . second = std : : floor ( std : : min ( display_range . first + max_chart_range , event_range . second ) * 10.0 ) / 10.0 ;
// reached the end, or seeked to a timestamp out of range.
if ( prev_range ! = display_range ) {
display_range . first = cur_sec - 5 ;
QFutureSynchronizer < void > future_synchronizer ;
}
for ( auto c : charts )
display_range . first = std : : floor ( std : : max ( min_event_sec , display_range . first ) ) ;
future_synchronizer . addFuture ( QtConcurrent : : run ( c , & ChartView : : setEventsRange , display_range ) ) ;
display_range . second = std : : floor ( std : : min ( display_range . first + max_chart_range , max_event_sec ) ) ;
if ( prev_range ! = display_range ) {
QFutureSynchronizer < void > future_synchronizer ;
for ( auto c : charts ) {
future_synchronizer . addFuture ( QtConcurrent : : run ( c , & ChartView : : setEventsRange , display_range ) ) ;
}
}
} else {
if ( cur_sec > = ( display_range . second - 5 ) ) {
display_range . first = std : : floor ( std : : max ( min_event_sec , cur_sec - settings . max_chart_x_range / 2.0 ) ) ;
}
display_range . second = std : : floor ( display_range . first + settings . max_chart_x_range ) ;
for ( auto c : charts ) {
c - > updateSeries ( nullptr , events , false ) ;
}
}
}
}
}
@ -151,7 +157,7 @@ void ChartsWidget::updateToolBar() {
bool displaying_all = max_chart_range ! = min_range ;
bool displaying_all = max_chart_range ! = min_range ;
show_all_values_btn - > setText ( tr ( " %1 minutes " ) . arg ( max_chart_range / 60 ) ) ;
show_all_values_btn - > setText ( tr ( " %1 minutes " ) . arg ( max_chart_range / 60 ) ) ;
show_all_values_btn - > setToolTip ( tr ( " Click to display %1 data " ) . arg ( displaying_all ? tr ( " %1 minutes " ) . arg ( min_range / 60 ) : tr ( " ALL cached " ) ) ) ;
show_all_values_btn - > setToolTip ( tr ( " Click to display %1 data " ) . arg ( displaying_all ? tr ( " %1 minutes " ) . arg ( min_range / 60 ) : tr ( " ALL cached " ) ) ) ;
show_all_values_btn - > setVisible ( ! is_zoomed ) ;
show_all_values_btn - > setVisible ( ! is_zoomed & & ! can - > liveStreaming ( ) ) ;
remove_all_btn - > setEnabled ( ! charts . isEmpty ( ) ) ;
remove_all_btn - > setEnabled ( ! charts . isEmpty ( ) ) ;
reset_zoom_btn - > setEnabled ( is_zoomed ) ;
reset_zoom_btn - > setEnabled ( is_zoomed ) ;
range_label - > setText ( is_zoomed ? tr ( " %1 - %2 " ) . arg ( zoomed_range . first , 0 , ' f ' , 2 ) . arg ( zoomed_range . second , 0 , ' f ' , 2 ) : " " ) ;
range_label - > setText ( is_zoomed ? tr ( " %1 - %2 " ) . arg ( zoomed_range . first , 0 , ' f ' , 2 ) . arg ( zoomed_range . second , 0 , ' f ' , 2 ) : " " ) ;
@ -274,6 +280,7 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
chart - > addAxis ( axis_y , Qt : : AlignLeft ) ;
chart - > addAxis ( axis_y , Qt : : AlignLeft ) ;
chart - > legend ( ) - > setShowToolTips ( true ) ;
chart - > legend ( ) - > setShowToolTips ( true ) ;
chart - > layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
chart - > layout ( ) - > setContentsMargins ( 0 , 0 , 0 , 0 ) ;
chart - > setMargins ( { 20 , 11 , 11 , 11 } ) ;
QToolButton * remove_btn = new QToolButton ( ) ;
QToolButton * remove_btn = new QToolButton ( ) ;
remove_btn - > setIcon ( bootstrapPixmap ( " x " ) ) ;
remove_btn - > setIcon ( bootstrapPixmap ( " x " ) ) ;
@ -293,7 +300,8 @@ ChartView::ChartView(QWidget *parent) : QChartView(nullptr, parent) {
setChart ( chart ) ;
setChart ( chart ) ;
setRenderHint ( QPainter : : Antialiasing ) ;
setRenderHint ( QPainter : : Antialiasing ) ;
setRubberBand ( QChartView : : HorizontalRubberBand ) ;
// TODO: enable zoomIn/seekTo in live streaming mode.
setRubberBand ( can - > liveStreaming ( ) ? QChartView : : NoRubberBand : QChartView : : HorizontalRubberBand ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : signalRemoved , this , & ChartView : : signalRemoved ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : signalRemoved , this , & ChartView : : signalRemoved ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : signalUpdated , this , & ChartView : : signalUpdated ) ;
QObject : : connect ( dbc ( ) , & DBCManager : : signalUpdated , this , & ChartView : : signalUpdated ) ;
@ -331,7 +339,6 @@ void ChartView::addSeries(const QString &msg_id, const Signal *sig) {
sigs . push_back ( { . msg_id = msg_id , . address = address , . source = source , . sig = sig , . series = series } ) ;
sigs . push_back ( { . msg_id = msg_id , . address = address , . source = source , . sig = sig , . series = series } ) ;
updateTitle ( ) ;
updateTitle ( ) ;
updateSeries ( sig ) ;
updateSeries ( sig ) ;
updateAxisY ( ) ;
emit seriesAdded ( msg_id , sig ) ;
emit seriesAdded ( msg_id , sig ) ;
}
}
@ -366,7 +373,6 @@ void ChartView::signalUpdated(const Signal *sig) {
updateTitle ( ) ;
updateTitle ( ) ;
// TODO: don't update series if only name changed.
// TODO: don't update series if only name changed.
updateSeries ( sig ) ;
updateSeries ( sig ) ;
updateAxisY ( ) ;
}
}
}
}
@ -448,22 +454,21 @@ void ChartView::setDisplayRange(double min, double max) {
}
}
}
}
void ChartView : : updateSeries ( const Signal * sig ) {
void ChartView : : updateSeries ( const Signal * sig , const std : : vector < Event * > * events , bool clear ) {
auto events = can - > events ( ) ;
if ( ! events ) events = can - > events ( ) ;
if ( ! events | | sigs . isEmpty ( ) ) return ;
if ( ! events | | sigs . isEmpty ( ) ) return ;
for ( auto & s : sigs ) {
for ( auto & s : sigs ) {
if ( ! sig | | s . sig = = sig ) {
if ( ! sig | | s . sig = = sig ) {
s . vals . clear ( ) ;
if ( clear ) {
s . vals . reserve ( ( events_range . second - events_range . first ) * 1000 ) ; // [n]seconds * 1000hz
s . vals . clear ( ) ;
s . min_y = std : : numeric_limits < double > : : max ( ) ;
s . last_value_mono_time = 0 ;
s . max_y = std : : numeric_limits < double > : : lowest ( ) ;
}
double route_start_time = can - > routeStartTime ( ) ;
double route_start_time = can - > routeStartTime ( ) ;
Event begin_event ( cereal : : Event : : Which : : INIT_DATA , ( route_start_time + events_range . first ) * 1e9 ) ;
uint64_t begin_ts = can - > liveStreaming ( ) ? s . last_value_mono_time : ( route_start_time + events_range . first ) * 1e9 ;
auto begin = std : : lower_bound ( events - > begin ( ) , events - > end ( ) , & begin_event , Event : : lessThan ( ) ) ;
Event begin_event ( cereal : : Event : : Which : : INIT_DATA , begin_ts ) ;
double end_ns = ( route_start_time + events_range . second ) * 1e9 ;
auto begin = std : : upper_bound ( events - > begin ( ) , events - > end ( ) , & begin_event , Event : : lessThan ( ) ) ;
uint64_t end_ns = can - > liveStreaming ( ) ? events - > back ( ) - > mono_time : ( route_start_time + events_range . second ) * 1e9 ;
for ( auto it = begin ; it ! = events - > end ( ) & & ( * it ) - > mono_time < = end_ns ; + + it ) {
for ( auto it = begin ; it ! = events - > end ( ) & & ( * it ) - > mono_time < = end_ns ; + + it ) {
if ( ( * it ) - > which = = cereal : : Event : : Which : : CAN ) {
if ( ( * it ) - > which = = cereal : : Event : : Which : : CAN ) {
for ( const auto & c : ( * it ) - > event . getCan ( ) ) {
for ( const auto & c : ( * it ) - > event . getCan ( ) ) {
@ -472,14 +477,20 @@ void ChartView::updateSeries(const Signal *sig) {
double value = get_raw_value ( ( uint8_t * ) dat . begin ( ) , dat . size ( ) , * s . sig ) ;
double value = get_raw_value ( ( uint8_t * ) dat . begin ( ) , dat . size ( ) , * s . sig ) ;
double ts = ( ( * it ) - > mono_time / ( double ) 1e9 ) - route_start_time ; // seconds
double ts = ( ( * it ) - > mono_time / ( double ) 1e9 ) - route_start_time ; // seconds
s . vals . push_back ( { ts , value } ) ;
s . vals . push_back ( { ts , value } ) ;
if ( value < s . min_y ) s . min_y = value ;
if ( value > s . max_y ) s . max_y = value ;
}
}
}
}
}
}
}
}
if ( ! s . vals . isEmpty ( ) ) {
auto [ min_v , max_v ] = std : : minmax_element ( s . vals . begin ( ) , s . vals . end ( ) , [ ] ( auto & l , auto & r ) { return l . y ( ) < r . y ( ) ; } ) ;
s . min_y = min_v - > y ( ) ;
s . max_y = max_v - > y ( ) ;
s . last_value_mono_time = events - > back ( ) - > mono_time ;
} else {
s . min_y = s . max_y = 0 ;
}
s . series - > replace ( s . vals ) ;
s . series - > replace ( s . vals ) ;
updateAxisY ( ) ;
}
}
}
}
}
}
@ -490,7 +501,7 @@ void ChartView::updateAxisY() {
double min_y = std : : numeric_limits < double > : : max ( ) ;
double min_y = std : : numeric_limits < double > : : max ( ) ;
double max_y = std : : numeric_limits < double > : : lowest ( ) ;
double max_y = std : : numeric_limits < double > : : lowest ( ) ;
if ( events_range = = std : : pair { axis_x - > min ( ) , axis_x - > max ( ) } ) {
if ( can - > liveStreaming ( ) | | events_range = = std : : pair { axis_x - > min ( ) , axis_x - > max ( ) } ) {
for ( auto & s : sigs ) {
for ( auto & s : sigs ) {
if ( s . min_y < min_y ) min_y = s . min_y ;
if ( s . min_y < min_y ) min_y = s . min_y ;
if ( s . max_y > max_y ) max_y = s . max_y ;
if ( s . max_y > max_y ) max_y = s . max_y ;
@ -583,7 +594,7 @@ void ChartView::mouseReleaseEvent(QMouseEvent *event) {
emit zoomIn ( min , max ) ;
emit zoomIn ( min , max ) ;
}
}
event - > accept ( ) ;
event - > accept ( ) ;
} else if ( event - > button ( ) = = Qt : : RightButton ) {
} else if ( ! can - > liveStreaming ( ) & & event - > button ( ) = = Qt : : RightButton ) {
emit zoomReset ( ) ;
emit zoomReset ( ) ;
event - > accept ( ) ;
event - > accept ( ) ;
} else {
} else {