/******************************************************************** Custom graph data Implementations Copyright (c)2011 Mark Watkins License: GPL *********************************************************************/ #include #include #include "graphdata_custom.h" /* WaveData::WaveData(MachineCode _code, int _size) :gPointData(_size),code(_code) { } WaveData::~WaveData() { } void WaveData::Reload(Day *day) { vc=0; if (!day) { m_ready=false; return; } min_x=day->first()/86400000.0; max_x=day->last()/86400000.0; if (max_x::iterator s=day->begin();s!=day->end(); s++) { //qDebug() << "Processing waveform chunk " << chunk++; if ((*s)->waveforms.find(code)==(*s)->waveforms.end()) continue; for (vector::iterator l=(*s)->waveforms[code].begin();l!=(*s)->waveforms[code].end();l++) { int ps=point.size(); if (vc>=ps) { AddSegment(max_points); // TODO: Add size limit capabilities. } int t=0; Waveform *w=(*l); double st=w->start()/86400000.0; double rate=double(w->duration())/w->samples()/86400000.0; //qDebug() << "Waveform Chunk contains " << w->samples() << " samples"; for (int i=0;isamples();i++) { QPointD r(st,(*w)[i]); st+=rate; (point[vc][t++])=r; if (t>=max_points) { qWarning()<< "WaveData max_points exceeded"; break; } //assert(tmax_y) max_y=r.y(); } } np[vc]=t; vc++; } } min_y=floor(min_y); max_y=ceil(max_y); //double t1=MAX(fabs(min_y),fabs(max_y)); // Get clever here.. if (min_y<0) { if (max_y>128) { double j=MAX(max_y,fabs(min_y)); min_y=-j; max_y=j; } else if (max_y>90) { max_y=120; min_y=-120; } else if (max_y>60) { min_y=-90; max_y=90; } else { min_y=-60; max_y=60; } } if (force_min_y!=force_max_y) { min_y=force_min_y; max_y=force_max_y; } real_min_x=min_x; real_min_y=min_y; real_max_x=max_x; real_max_y=max_y; m_ready=true; //graph->Refresh(false); } EventData::EventData(MachineCode _code,int _field,int _size,bool _skipzero) :gPointData(_size),code(_code),field(_field),skipzero(_skipzero) { } EventData::~EventData() { } void EventData::Reload(Day *day) { vc=0; if (!day) { m_ready=false; return; } min_x=day->first()/86400000.0; max_x=day->last()/86400000.0; if (min_x>max_x) { qWarning() << "EventData min_x > max_x"; return; } min_y=max_y=0; int tt=0; bool first=true; EventDataType lastp=0; for (vector::iterator s=day->begin();s!=day->end(); s++) { if ((*s)->events.find(code)==(*s)->events.end()) continue; if (vc>=(int)point.size()) { AddSegment(max_points); } int t=0; EventDataType p; for (vector::iterator ev=(*s)->events[code].begin(); ev!=(*s)->events[code].end(); ev++) { p=(*(*ev))[field]; if (((p!=0) && skipzero) || !skipzero) { QPointD r((*ev)->time()/86400000.0,p); point[vc][t++]=r; if (t>=max_points) { qWarning() << "EventData max_points exceeded"; break; } if (first) { max_y=min_y=r.y(); //lastp=p; first=false; } else { if (r.y()max_y) max_y=r.y(); } } else { if ((p!=lastp) && (t>0)) { // There really should not be consecutive zeros.. just in case.. np[vc]=t; tt+=t; t=0; vc++; if (vc>=(int)point.size()) { AddSegment(max_points); } } } lastp=p; } np[vc]=t; if (t>0) { tt+=t; vc++; } } if (tt>0) { min_y=floor(min_y); max_y=ceil(max_y+1); if (min_y>1) min_y-=1; } if (force_min_y!=force_max_y) { min_y=force_min_y; max_y=force_max_y; } real_min_x=min_x; real_min_y=min_y; real_max_x=max_x; real_max_y=max_y; m_ready=true; } TAPData::TAPData(MachineCode _code) :gPointData(256),code(_code) { AddSegment(max_points); } TAPData::~TAPData() { } void TAPData::Reload(Day *day) { if (!day) { m_ready=false; return; } for (int i=0;i::iterator s=day->begin();s!=day->end();s++) { if ((*s)->events.find(code)==(*s)->events.end()) continue; first=true; for (vector::iterator e=(*s)->events[code].begin(); e!=(*s)->events[code].end(); e++) { Event & ev =(*(*e)); val=ev[field]*10.0; if (field>=ev.fields()) { qWarning() << "Invalid Event field in TAPData::Reload"; return; } //if (field > ev.fields()) throw BoundsError(); if (first) { first=false; // only bother setting lastval (below) this time. } else { double d=(ev.time()-last)/1000.0; if (lastval>=max_slots) { qWarning() << "TapData: lastval0) { point[0][jj].setX(i/10.0); point[0][jj].setY((100.0/TotalTime)*pTime[i]); jj++; } } np[0]=jj; //graph->Refresh(); m_ready=true; } AHIData::AHIData() :gPointData(256) { AddSegment(max_points); } AHIData::~AHIData() { } void AHIData::Reload(Day *day) { if (!day) { m_ready=false; return; } point[0][0].setY(day->count(CPAP_Hypopnea)/day->hours()); point[0][0].setX(point[0][0].y()); point[0][1].setY(day->count(CPAP_Obstructive)/day->hours()); point[0][1].setX(point[0][1].y()); point[0][2].setY(day->count(CPAP_ClearAirway)/day->hours()); point[0][2].setX(point[0][2].y()); point[0][3].setY(day->count(CPAP_RERA)/day->hours()); point[0][3].setX(point[0][3].y()); point[0][4].setY(day->count(CPAP_FlowLimit)/day->hours()); point[0][4].setX(point[0][4].y()); //point[0][5].setY((100.0/day->hours())*(day->sum(CPAP_CSR)/3600.0)); //point[0][5].setX(point[0][5].y()); np[0]=5; m_ready=true; //REFRESH?? } FlagData::FlagData(MachineCode _code,int _field,int _offset) :gPointData(65536),code(_code),field(_field),offset(_offset) { AddSegment(max_points); } FlagData::~FlagData() { } void FlagData::Reload(Day *day) { if (!day) { m_ready=false; return; } int c=0; vc=0; double v1,v2; //bool first; min_x=day->first()/86400000.0; max_x=day->last()/86400000.0; bool done=false; for (vector::iterator s=day->begin();s!=day->end();s++) { if ((*s)->events.find(code)==(*s)->events.end()) continue; //first=true; for (vector::iterator e=(*s)->events[code].begin(); e!=(*s)->events[code].end(); e++) { Event & ev =(*(*e)); v2=v1=ev.time()/86400000.0; if (offset>=0) v1-=ev[offset]/86400.0; point[vc][c].setX(v1); point[vc][c].setY(v2); v1=point[vc][c].x(); v2=point[vc][c].y(); c++; if (c>=max_points) { qWarning() << "FlagData: max_points exceeded"; done=true; break; } if (first) { min_y=v1; first=false; } else { if (v1max_x) max_x=v2; } if (done) break; } min_y=0;//-value; max_y=1;//value; np[vc]=c; vc++; real_min_x=min_x; real_min_y=min_y; real_max_x=max_x; real_max_y=max_y; m_ready=true; } //////////////////////////////////////////////////////////////////////////////////////////// // Session Times Implementation //////////////////////////////////////////////////////////////////////////////////////////// SessionTimes::SessionTimes(Profile * _profile) :HistoryData(_profile,2048) { //AddSegment(max_points); //if (profile->LastDay().isValid()) { // QDateTime tmp; // tmp.setDate(profile->FirstDay()); // real_min_x=tmp.toMSecsSinceEpoch()/86400000.0; // tmp.setDate(profile->LastDay()); // real_max_x=(tmp.toMSecsSinceEpoch()/86400000.0)+1; //} //real_min_y=real_max_y=0; } SessionTimes::~SessionTimes() { } void SessionTimes::ResetDateRange() { if (profile->LastDay().isValid()) { QDateTime tmp; tmp.setDate(profile->FirstDay()); real_min_x=tmp.toMSecsSinceEpoch()/86400000.0; tmp.setDate(profile->LastDay()); real_max_x=(tmp.toMSecsSinceEpoch()/86400000.0)+1; } } double SessionTimes::GetAverage() { double x,val=0; int cnt=0; for (int i=0;imax_x)) continue; val+=point[0][i].y()-point[0][i].x(); cnt++; } if (!cnt) return 0; val/=cnt; return val; } void SessionTimes::SetDateRange(QDate start,QDate end) { qint64 x1=QDateTime(start).toMSecsSinceEpoch()/86400000.0; qint64 x2=QDateTime(end.addDays(1)).toMSecsSinceEpoch()/86400000.0; if (x1 < real_min_x) x1=real_min_x; if (x2 > (real_max_x)) x2=(real_max_x); min_x=x1; max_x=x2; for (list::iterator i=notify_layers.begin();i!=notify_layers.end();i++) { (*i)->DataChanged(this); } // Do nothing else.. Callers responsibility to Refresh window. } void SessionTimes::Reload(Day *day) { day=day; //shuttup warnings.. we don't use this. QDateTime date; vc=0; bool done=false; double st,et; min_y=max_y=0; min_x=max_x=0; if (real_min_x<0) return; if (real_max_x<0) return; int i=0; for (double x=floor(real_min_x);x<=ceil(real_max_x);x++) { date=QDateTime::fromMSecsSinceEpoch(x*86400000.0L); // Ouch.. QDateTime conversions are slow as hell.. // date.setTime(QTime(0,0,0)); //if (profile->daylist.find(date.date())==profile->daylist.end()) continue; Day *dy=profile->GetDay(date.date(),MT_CPAP); if (!dy) continue; //vector & daylist=profile->daylist[date.date()]; for (vector::iterator dd=dy->begin(); dd!=dy->end(); dd++) { // average any multiple data sets st=double((*dd)->first())/86400000.0; et=double((*dd)->last())/86400000.0; point[vc][i].setX(st); point[vc][i].setY(et); i++; if (i>max_points) { qWarning("max_points is not enough in HistoryData"); done=true; break; } } if (done) break; } np[vc]=i; vc++; min_x=real_min_x; max_x=real_max_x; if (force_min_y!=force_max_y) { min_y=force_min_y; max_y=force_max_y; } else { min_y=-12; max_y=+12; } real_min_y=min_y; real_max_y=max_y; m_ready=true; } //////////////////////////////////////////////////////////////////////////////////////////// // HistoryData Implementation //////////////////////////////////////////////////////////////////////////////////////////// HistoryData::HistoryData(Profile * _profile,int mpts) :gPointData(mpts),profile(_profile) { AddSegment(max_points); if (profile->LastDay().isValid()) { QDateTime tmp; tmp.setDate(profile->FirstDay()); real_min_x=tmp.toMSecsSinceEpoch()/86400000.0; tmp.setDate(profile->LastDay()); real_max_x=(tmp.toMSecsSinceEpoch()/86400000.0)+1; } real_min_y=real_max_y=0; } HistoryData::~HistoryData() { } void HistoryData::ResetDateRange() { if (profile->LastDay().isValid()) { QDateTime tmp; tmp.setDate(profile->FirstDay()); real_min_x=tmp.toMSecsSinceEpoch()/86400000.0; tmp.setDate(profile->LastDay()); real_max_x=(tmp.toMSecsSinceEpoch()/86400000.0)+1; } // Reload(NULL); } double HistoryData::Calc(Day *day) { double h=day->hours(); double ahi=(day->summary_sum(CPAP_Obstructive) + day->summary_sum(CPAP_Hypopnea) + day->summary_sum(CPAP_ClearAirway)) / h; if (ahi>1000) { ahi=999; } return ahi; } void HistoryData::Reload(Day *day) { day=day; //shuttup warnings.. QDateTime date; vc=0; int i=0; bool first=true; bool done=false; double y,lasty; min_y=max_y=0; min_x=max_x=0; if (real_min_x<0) return; if (real_max_x<0) return; for (double x=floor(real_min_x);x<=ceil(real_max_x);x++) { date=QDateTime::fromMSecsSinceEpoch(x*86400000.0L); date.setTime(QTime(0,0,0)); if (profile->daylist.find(date.date())==profile->daylist.end()) continue; y=0; int z=0; vector & daylist=profile->daylist[date.date()]; for (vector::iterator dd=daylist.begin(); dd!=daylist.end(); dd++) { // average any multiple data sets Day *d=(*dd); if (d->machine_type()==MT_CPAP) { y+=Calc(d); z++; } } if (!z) continue; if (z>1) y /= z; if (first) { // max_x=min_x=x; lasty=max_y=min_y=y; first=false; } point[vc][i].setX(x); point[vc][i].setY(y); if (y>max_y) max_y=y; if (ymax_x) max_x=x; i++; if (i>max_points) { qWarning("max_points is not enough in HistoryData"); done=true; } if (done) break; lasty=y; } np[vc]=i; vc++; min_x=real_min_x; max_x=real_max_x; // max_x+=1; //real_min_x=min_x; //real_max_x=max_x; if (force_min_y!=force_max_y) { min_y=force_min_y; max_y=force_max_y; } else { if (!((min_y==max_y) && (min_y==0))) { if (min_y>1) min_y-=1; max_y++; } } // assert(max_y<10000000); real_min_y=min_y; real_max_y=max_y; m_ready=true; } void HistoryData::SetDateRange(QDate start,QDate end) { qint64 x1=QDateTime(start).toMSecsSinceEpoch()/86400000.0; qint64 x2=QDateTime(end.addDays(1)).toMSecsSinceEpoch()/86400000.0; if (x1 < real_min_x) x1=real_min_x; if (x2 > (real_max_x)) x2=(real_max_x); min_x=x1; max_x=x2; for (list::iterator i=notify_layers.begin();i!=notify_layers.end();i++) { (*i)->DataChanged(this); } // Do nothing else.. Callers responsibility to Refresh window. } HistoryCodeData::HistoryCodeData(Profile *_profile,MachineCode _code) :HistoryData(_profile),code(_code) { } HistoryCodeData::~HistoryCodeData() { } double HistoryCodeData::Calc(Day *day) { return day->summary_avg(code); } UsageHistoryData::UsageHistoryData(Profile *_profile,T_UHD _uhd) :HistoryData(_profile),uhd(_uhd) { } UsageHistoryData::~UsageHistoryData() { } double UsageHistoryData::Calc(Day *day) { qint64 d; double h; if (uhd==UHD_Bedtime) { d=day->first()/1000; d%=86400; h=d/3600; if (h<12) h+=24; h+=1.0/float(d%3600); //d+=(day->first().time().minute()/60.0); //d+=(day->first().time().second()/3600.0); return h; } else if (uhd==UHD_Waketime) { d=day->first()/1000; d%=86400; h=d/3600; h+=1.0/float(d%3600); //d=day->last().time().hour(); //d+=(day->last().time().minute()/60.0); //d+=(day->last().time().second()/3600.0); return h; } else if (uhd==UHD_Hours) { return day->hours(); } else return 0; } */