Go to the documentation of this file.00001 #include "timeseries_qwt.h"
00002 #include <limits>
00003 #include <stdexcept>
00004 #include <QMessageBox>
00005 #include <QString>
00006
00007 TimeseriesQwt::TimeseriesQwt(PlotDataPtr base):
00008 _plot_data(base),
00009 _subsample(1),
00010 _transform( noTransform ),
00011 _time_offset(0)
00012 {
00013 updateData();
00014 }
00015
00016 QPointF TimeseriesQwt::sample(size_t i) const
00017 {
00018 if(_transform == noTransform)
00019 {
00020 auto p = _plot_data->at(i);
00021 return QPointF(p.x - _time_offset, p.y);
00022 }
00023 return _cached_transformed_curve[i];
00024 }
00025
00026 QRectF TimeseriesQwt::boundingRect() const
00027 {
00028 return _bounding_box;
00029 }
00030
00031 size_t TimeseriesQwt::size() const
00032 {
00033 if(_transform == noTransform){
00034 return _plot_data->size();
00035 }
00036 return _cached_transformed_curve.size();
00037 }
00038
00039 void TimeseriesQwt::setSubsampleFactor()
00040 {
00041
00042 }
00043
00044 void TimeseriesQwt::updateData()
00045 {
00046 if(_plot_data->size() == 0) return;
00047
00048 double min_y =( std::numeric_limits<double>::max() );
00049 double max_y =(-std::numeric_limits<double>::max() );
00050 double min_x =( std::numeric_limits<double>::max() );
00051 double max_x =(-std::numeric_limits<double>::max() );
00052
00053
00054 {
00055 if(_transform == noTransform)
00056 {
00057 _cached_transformed_curve.resize( 0 );
00058 _cached_transformed_curve.shrink_to_fit();
00059
00060 for (size_t i=0; i< _plot_data->size(); i++ )
00061 {
00062 auto p = _plot_data->at( i );
00063 p.x -= _time_offset;
00064
00065 if(min_y > p.y) min_y =(p.y);
00066 else if(max_y < p.y) max_y =(p.y);
00067
00068 if(min_x > p.x) min_x =(p.x);
00069 else if(max_x < p.x) max_x =(p.x);
00070 }
00071 }
00072 else if(_transform == firstDerivative)
00073 {
00074 if( _plot_data->size() < 1){
00075 _cached_transformed_curve.clear();
00076 }
00077 else{
00078 _cached_transformed_curve.resize( _plot_data->size() - 1 );
00079 }
00080
00081 for (size_t i=0; i< _plot_data->size() -1; i++ )
00082 {
00083 const auto& p0 = _plot_data->at( i );
00084 const auto& p1 = _plot_data->at( i+1 );
00085 const auto delta = p1.x - p0.x;
00086 const auto vel = (p1.y - p0.y) /delta;
00087 QPointF p( (p1.x + p0.x)*0.5, vel);
00088 p.setX( p.x() - _time_offset);
00089 _cached_transformed_curve[i] = p;
00090
00091 if(min_y > p.y()) min_y =(p.y());
00092 else if(max_y < p.y()) max_y =(p.y());
00093
00094 if(min_x > p.x()) min_x =(p.x());
00095 else if(max_x < p.x()) max_x =(p.x());
00096 }
00097 }
00098 else if(_transform == secondDerivative)
00099 {
00100 if( _plot_data->size() < 2){
00101 _cached_transformed_curve.clear();
00102 }
00103 else{
00104 _cached_transformed_curve.resize( _plot_data->size() - 2 );
00105 }
00106
00107 for (size_t i=0; i< _cached_transformed_curve.size(); i++ )
00108 {
00109 const auto& p0 = _plot_data->at( i );
00110 const auto& p1 = _plot_data->at( i+1 );
00111 const auto& p2 = _plot_data->at( i+2 );
00112 const auto delta = (p2.x - p0.x) *0.5;
00113 const auto acc = ( p2.y - 2.0* p1.y + p0.y)/(delta*delta);
00114 QPointF p( (p2.x + p0.x)*0.5, acc );
00115 p.setX( p.x() - _time_offset);
00116 _cached_transformed_curve[i] = p;
00117
00118 if(min_y > p.y()) min_y =(p.y());
00119 else if(max_y < p.y()) max_y =(p.y());
00120
00121 if(min_x > p.x()) min_x =(p.x());
00122 else if(max_x < p.x()) max_x =(p.x());
00123 }
00124 }
00125 else if( _transform == XYPlot && _alternative_X_axis)
00126 {
00127 bool failed = false;
00128 const size_t N = _alternative_X_axis->size();
00129
00130 if( _plot_data->size() != N ){
00131 failed = true ;
00132 }
00133
00134 for (size_t i=0; i<N && !failed; i++ )
00135 {
00136 if( _alternative_X_axis->at(i).x != _plot_data->at(i).x ){
00137 failed = true ;
00138 break;
00139 }
00140 }
00141
00142 if( failed){
00143 QMessageBox::warning(0, QString("Warning"),
00144 QString("The creation of the XY plot failed because at least two "
00145 "timeseries don't share the same time axis.") );
00146 return;
00147 }
00148 else{
00149 _cached_transformed_curve.resize(N);
00150 for (size_t i=0; i<N; i++ )
00151 {
00152 const QPointF p(_alternative_X_axis->at(i).y, _plot_data->at(i).y );
00153 _cached_transformed_curve[i] = p;
00154
00155 if(min_y > p.y()) min_y =(p.y());
00156 else if(max_y < p.y()) max_y =(p.y());
00157
00158 if(min_x > p.x()) min_x =(p.x());
00159 else if(max_x < p.x()) max_x =(p.x());
00160 }
00161 }
00162 }
00163 }
00164 _bounding_box.setBottom(min_y);
00165 _bounding_box.setTop(max_y);
00166 _bounding_box.setLeft(min_x);
00167 _bounding_box.setRight(max_x);
00168 }
00169
00170 PlotData::RangeTimeOpt TimeseriesQwt::getVisualizationRangeX()
00171 {
00172
00173 if( this->size() < 2 )
00174 return PlotData::RangeTimeOpt();
00175 else{
00176 return PlotData::RangeTimeOpt( { _bounding_box.left(), _bounding_box.right() } );
00177 }
00178 }
00179
00180
00181 PlotData::RangeValueOpt TimeseriesQwt::getVisualizationRangeY(int first_index, int last_index)
00182 {
00183 if( first_index < 0 || last_index < 0 || first_index > last_index)
00184 {
00185 return PlotData::RangeValueOpt();
00186 }
00187
00188 if( (_transform == XYPlot && _alternative_X_axis) ||
00189 ( first_index==0 && last_index == size() -1) )
00190 {
00191 return PlotData::RangeValueOpt( { _bounding_box.bottom(), _bounding_box.top() } );
00192 }
00193
00194 const double first_Y = sample(first_index).y();
00195 double y_min = first_Y;
00196 double y_max = first_Y;
00197
00198 for (int i = first_index+1; i < last_index; i++)
00199 {
00200 const double Y = sample(i).y();
00201
00202 if( Y < y_min ) y_min = Y;
00203 else if( Y > y_max ) y_max = Y;
00204 }
00205 return PlotData::RangeValueOpt( { y_min, y_max } );
00206 }
00207
00208 void TimeseriesQwt::setAlternativeAxisX(PlotDataPtr new_x_data)
00209 {
00210 _alternative_X_axis = new_x_data;
00211 }
00212
00213 nonstd::optional<QPointF> TimeseriesQwt::sampleFromTime(double t)
00214 {
00215 if( _transform == XYPlot && _alternative_X_axis)
00216 {
00217 auto res1 = _alternative_X_axis->getYfromX( t );
00218 if( res1)
00219 {
00220 auto res2 = _plot_data->getYfromX( t );
00221 if( res2 ){
00222 return nonstd::optional<QPointF>(
00223 QPointF(res1.value(), res2.value() ) ) ;
00224 }
00225 }
00226 }
00227 else{
00228 auto res = _plot_data->getYfromX( t );
00229 if(res){
00230 return nonstd::optional<QPointF>( QPointF(t, res.value() ) ) ;
00231 }
00232 }
00233 return nonstd::optional<QPointF>();
00234 }
00235
00236 void TimeseriesQwt::setTransform(TimeseriesQwt::Transform trans)
00237 {
00238 if(trans != _transform)
00239 {
00240 _transform = trans;
00241 updateData();
00242 }
00243 }
00244
00245 void TimeseriesQwt::setTimeOffset(double offset)
00246 {
00247 _time_offset = offset;
00248 updateData();
00249 }