Event System Mega Overhaul

This commit is contained in:
Mark Watkins 2011-07-27 19:21:53 +10:00
parent 10e96281e9
commit f9796306ca
52 changed files with 2257 additions and 2313 deletions

View File

@ -8,8 +8,8 @@
#include <SleepLib/profiles.h>
#include "gBarChart.h"
gBarChart::gBarChart(gPointData *d,QColor col,Qt::Orientation o)
:gLayer(d),m_orientation(o)
gBarChart::gBarChart(MachineCode code,QColor col,Qt::Orientation o)
:gLayer(code),m_orientation(o)
{
color.clear();
color.push_back(col);
@ -24,7 +24,7 @@ gBarChart::~gBarChart()
void gBarChart::Plot(gGraphWindow & w,float scrx,float scry)
{
if (!m_visible) return;
if (!data) return;
/*if (!data) return;
if (!data->IsReady()) return;
int start_px=w.GetLeftMargin();
@ -168,6 +168,6 @@ void gBarChart::Plot(gGraphWindow & w,float scrx,float scry)
//glVertex2f (start_px,start_py);
//glVertex2f (start_px+width, start_py);
glEnd ();
*/
}

View File

@ -12,7 +12,7 @@
class gBarChart:public gLayer
{
public:
gBarChart(gPointData *d=NULL,QColor col=QColor("blue"),Qt::Orientation o=Qt::Horizontal);
gBarChart(MachineCode code=MC_UNKNOWN,QColor col=QColor("blue"),Qt::Orientation o=Qt::Horizontal);
virtual ~gBarChart();
virtual void Plot(gGraphWindow & w,float scrx,float scry);
@ -22,10 +22,10 @@ class gBarChart:public gLayer
// d.Set(i+2400000.5+.000001); // JDN vs MJD vs Rounding errors
virtual const QString & FormatX(double v) { static QString t; QDateTime d; d=d.fromMSecsSinceEpoch(v*86400000.0); t=d.toString("MMM dd"); return t; };
virtual const QString & FormatX(double v) { static QString t; QDateTime d; d=d.fromMSecsSinceEpoch(v*86400000.0); t=d.toString("MMM dd"); return t; }
//virtual const wxString & FormatX(double v) { static wxString t; wxDateTime d; d.Set(vi*86400000.0); t=d.Format(wxT("HH:mm")); return t; };
//virtual const wxString & FormatX(double v) { static wxString t; t=wxString::Format(wxT("%.1f"),v); return t; };
virtual const QString & FormatY(double v) { static QString t; t.sprintf("%.1f",v); return t; };
virtual const QString & FormatY(double v) { static QString t; t.sprintf("%.1f",v); return t; }
gXAxis *Xaxis;
};

View File

@ -7,8 +7,8 @@
#include <math.h>
#include "gCandleStick.h"
gCandleStick::gCandleStick(gPointData *d,Qt::Orientation o)
:gLayer(d)
gCandleStick::gCandleStick(MachineCode code,Qt::Orientation o)
:gLayer(code)
{
m_orientation=o;
}
@ -18,7 +18,7 @@ gCandleStick::~gCandleStick()
void gCandleStick::Plot(gGraphWindow & w,float scrx,float scry)
{
if (!m_visible) return;
if (!data) return;
/*if (!data) return;
if (!data->IsReady()) return;
int start_px=w.GetLeftMargin();
@ -113,6 +113,6 @@ void gCandleStick::Plot(gGraphWindow & w,float scrx,float scry)
}
}
} // for (int i
glFlush();
glFlush(); */
}

View File

@ -12,7 +12,7 @@
class gCandleStick:public gLayer
{
public:
gCandleStick(gPointData *d=NULL,Qt::Orientation o=Qt::Horizontal);
gCandleStick(MachineCode code=MC_UNKNOWN,Qt::Orientation o=Qt::Horizontal);
virtual ~gCandleStick();
virtual void Plot(gGraphWindow & w,float scrx,float scry);

View File

@ -15,30 +15,45 @@ gFlagsGroup::gFlagsGroup()
gFlagsGroup::~gFlagsGroup()
{
}
qint64 gFlagsGroup::Minx()
{
if (m_day) {
return m_day->first();
}
return 0;
}
qint64 gFlagsGroup::Maxx()
{
if (m_day) {
return m_day->last();
}
return 0;
}
void gFlagsGroup::Plot(gGraphWindow &w, float scrx, float scry)
{
if (!m_visible) return;
//if (!m_day) return;
int start_px=w.GetLeftMargin();
int start_py=w.GetBottomMargin();
int width=scrx-(w.GetLeftMargin()+w.GetRightMargin())-1;
int height=scry-(w.GetTopMargin()+w.GetBottomMargin());
vector<gFlagsLine *> visible;
vector<gFlagsLine *> lvisible;
for (unsigned i=0;i<layers.size();i++) {
gFlagsLine *f=dynamic_cast<gFlagsLine *>(layers[i]);
if (!f) continue;
if (!f->isEmpty() || f->isAlwaysVisible()) {
visible.push_back(f);
lvisible.push_back(f);
}
}
int vis=visible.size();
for (unsigned i=0;i<visible.size();i++) {
visible[i]->line_num=i;
visible[i]->total_lines=vis;
visible[i]->Plot(w,scrx,scry);
int vis=lvisible.size();
for (unsigned i=0;i<lvisible.size();i++) {
lvisible[i]->line_num=i;
lvisible[i]->total_lines=vis;
lvisible[i]->Plot(w,scrx,scry);
}
glColor3f (0.0F, 0.0F, 0.0F);
glLineWidth (1);
@ -52,12 +67,11 @@ void gFlagsGroup::Plot(gGraphWindow &w, float scrx, float scry)
}
gFlagsLine::gFlagsLine(gPointData *d,QColor col,QString _label,bool always_visible)
:gLayer(d),label(_label),m_always_visible(always_visible)
gFlagsLine::gFlagsLine(MachineCode code,QColor col,QString _label,bool always_visible,FLT_Type flt)
:gLayer(code),label(_label),m_always_visible(always_visible),m_flt(flt)
{
color.clear();
color.push_back(col);
}
gFlagsLine::~gFlagsLine()
{
@ -65,8 +79,7 @@ gFlagsLine::~gFlagsLine()
void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry)
{
if (!m_visible) return;
if (!data) return;
if (!data->IsReady()) return;
if (!m_day) return;
double minx;
double maxx;
@ -132,21 +145,25 @@ void gFlagsLine::Plot(gGraphWindow & w,float scrx,float scry)
float top=floor(line_top)+2;
float bottom=top+floor(line_h)-3;
for (int n=0;n<data->VC();n++) {
if (!data->np[n]) continue;
qint64 X,Y;
for (vector<Session *>::iterator s=m_day->begin();s!=m_day->end(); s++) {
if ((*s)->eventlist.find(m_code)==(*s)->eventlist.end()) continue;
for (int i=0;i<data->np[n];i++) {
QPointD & rp=data->point[n][i];
if (rp.y() < minx) continue;
if (rp.x() > maxx) break;
x1=(rp.x() - minx) * xmult + w.GetLeftMargin();
if (rp.x()==rp.y()) {
EventList & el=*((*s)->eventlist[m_code][0]);
for (int i=0;i<el.count();i++) {
X=el.time(i);
Y=X-(el.data(i)*1000);
if (Y < minx) continue;
if (X > maxx) break;
x1=(X - minx) * xmult + w.GetLeftMargin();
if (m_flt==FLT_Bar) {
vertarray[vertcnt++]=x1;
vertarray[vertcnt++]=top;
vertarray[vertcnt++]=x1;
vertarray[vertcnt++]=bottom;
} else {
x2=(rp.y()-minx)*xmult+w.GetLeftMargin();
} else if (m_flt==FLT_Span) {
x2=(Y-minx)*xmult+w.GetLeftMargin();
//w1=x2-x1;
quadarray[quadcnt++]=x1;
quadarray[quadcnt++]=top;

View File

@ -11,11 +11,13 @@
class gFlagsGroup;
enum FLT_Type { FLT_Bar, FLT_Span, FLT_Dot };
class gFlagsLine:public gLayer
{
friend class gFlagsGroup;
public:
gFlagsLine(gPointData *d=NULL,QColor col=Qt::black,QString _label="",bool always_visible=false);
gFlagsLine(MachineCode code,QColor col=Qt::black,QString _label="",bool always_visible=false,FLT_Type flt=FLT_Bar);
virtual ~gFlagsLine();
virtual void Plot(gGraphWindow & w,float scrx,float scry);
@ -23,12 +25,13 @@ class gFlagsLine:public gLayer
void setAlwaysVisible(bool b) { m_always_visible=b; }
QString Label() { return label; }
void Label(QString s) { label=s; }
void setTotalLines(int i) { total_lines=i; };
void setLineNum(int i) { line_num=i; };
void setTotalLines(int i) { total_lines=i; }
void setLineNum(int i) { line_num=i; }
protected:
QString label;
bool m_always_visible;
int total_lines,line_num;
FLT_Type m_flt;
};
class gFlagsGroup:public gLayerGroup
@ -38,6 +41,9 @@ public:
virtual ~gFlagsGroup();
virtual void Plot(gGraphWindow &w, float scrx, float scry);
virtual qint64 Minx();
virtual qint64 Maxx();
};
#endif // GFLAGSLINE_H

View File

@ -7,7 +7,7 @@
#include "gFooBar.h"
gFooBar::gFooBar(int offset,QColor col1,QColor col2,bool funkbar)
:gLayer(NULL),m_funkbar(funkbar),m_offset(offset)
:gLayer(MC_UNKNOWN),m_funkbar(funkbar),m_offset(offset)
{
color.clear();
color.push_back(col2);

View File

@ -11,42 +11,71 @@
#include "gLineChart.h"
#define EXTRA_ASSERTS 1
gLineChart::gLineChart(gPointData *d,QColor col,int dlsize,bool _accelerate,bool _hide_axes,bool _square_plot)
:gLayer(d),m_accelerate(_accelerate),m_drawlist_size(dlsize),m_hide_axes(_hide_axes),m_square_plot(_square_plot)
gLineChart::gLineChart(MachineCode code,QColor col,bool _square_plot)
:gLayer(code),m_square_plot(_square_plot)
{
m_drawlist=new QPointD [dlsize];
color.clear();
color.push_back(col);
m_report_empty=false;
}
gLineChart::~gLineChart()
{
delete [] m_drawlist;
}
// Time Domain Line Chart
void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
{
const int max_drawlist_size=4096;
static QPoint m_drawlist[max_drawlist_size];
if (!m_visible)
return;
if (!data)
if (!m_day)
return;
if (!data->IsReady())
return;
if (w.Title()=="Plethysomogram") {
int q=0;
int start_px=w.GetLeftMargin();
int start_py=w.GetBottomMargin();
int width=scrx-(w.GetLeftMargin()+w.GetRightMargin());
int height=scry-(w.GetTopMargin()+w.GetBottomMargin())-2;
double miny,maxy,minx,maxx;
miny=w.min_y, maxy=w.max_y, maxx=w.max_x, minx=w.min_x;
int m;
if (maxy>500) {
m=ceil(maxy/100.0);
maxy=m*100;
m=floor(miny/100.0);
miny=m*100;
} else if (maxy>150) {
m=ceil(maxy/50.0);
maxy=m*50;
m=floor(miny/50.0);
miny=m*50;
} else if (maxy>80) {
m=ceil(maxy/20.0);
maxy=m*20;
m=floor(miny/20.0);
miny=m*20;
} else if (maxy>30) {
m=ceil(maxy/10.0);
maxy=m*10;
m=floor(miny/10.0);
miny=m*10;
} else if (maxy>5) {
m=ceil(maxy/5.0);
maxy=m*5;
m=floor(miny/5.0);
miny=m*5;
} else {
// qDebug() << w.Title();
maxy=ceil(maxy);
if (maxy<1) maxy=1;
miny=floor(miny);
//if (miny<1) miny=0;
}
int start_px=w.GetLeftMargin(), start_py=w.GetBottomMargin();
int width=scrx-(w.GetLeftMargin()+w.GetRightMargin());
int height=scry-(w.GetTopMargin()+w.GetBottomMargin());
double minx=w.min_x, miny=w.min_y, maxx=w.max_x, maxy=w.max_y;
double xx=maxx-minx, yy=maxy-miny;
float xmult=width/xx, ymult=height/yy; // time to pixel conversion multiplier
float xmult=width/xx, ymult=(height)/yy; // time to pixel conversion multiplier
// Return on screwy min/max conditions
if ((xx<0) || (yy<0))
@ -54,43 +83,27 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
if ((yy==0) && (miny==0))
return;
int num_points=0;
for (int z=0;z<data->VC();z++) num_points+=data->np[z]; // how many points all up?
float lastpx,lastpy;
float px,py;
int idx,idxend,np;
bool done,first;
double x0,x1,xL;
double sr;
int sam;
int minz,maxz;
// Draw bounding box if something else will be drawn.
if (!(!m_report_empty && !num_points)) {
glColor3f (0.1F, 0.1F, 0.1F);
// Draw bounding box
{
glColor3f (0.0, 0.0, 0.0);
glLineWidth (1);
glBegin (GL_LINE_LOOP);
glVertex2f (start_px, start_py);
glVertex2f (start_px, start_py+height);
glVertex2f (start_px+width,start_py+height);
glVertex2f (start_px, start_py+height+2);
glVertex2f (start_px+width,start_py+height+2);
glVertex2f (start_px+width, start_py);
glEnd ();
}
width--;
if (!num_points) { // No Data?
if (m_report_empty) {
QString msg="No Waveform Available";
float x,y;
//TextMarkup...
GetTextExtent(msg,x,y,bigfont);
//w.renderText(start_px+(width/2.0)-(x/2.0),start_py+(height/2.0)-(y/2.0),msg,*bigfont);
DrawText(msg,start_px+(width/2.0)-(x/2.0),scry-w.GetBottomMargin()-height/2.0+y/2.0,0,Qt::gray,bigfont);//-(y/2.0)
}
return;
}
bool square_plot=m_square_plot;
if (num_points>500) {
square_plot=false;
}
bool accel=m_accelerate;
double sr;
int dp,sam;
QColor & col=color[0];
// Selected the plot line color
qint32 vertcnt=0;
GLshort * vertarray=vertex_array[0];
@ -99,54 +112,69 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
return;
}
float lastpx,lastpy;
float px,py;
int idx,idxend,np;
bool done,first;
double x0,x1,xL;
// Selected the plot line color
QColor & col=color[0];
int num_points=0;
int visible_points=0;
int total_points=0;
int total_visible=0;
bool square_plot,accel;
for (int n=0;n<data->VC();n++) { // for each segment
for (vector<Session *>::iterator s=m_day->begin(); s!=m_day->end(); s++) {
vector<EventList *> & evec=(*s)->eventlist[m_code];
if (evec.size()==0) continue; // not possible
int siz=data->np[n];
num_points=0;
for (unsigned i=0;i<evec.size();i++) num_points+=evec[i]->count();
if (!num_points) continue;
total_points+=num_points;
for (unsigned n=0;n<evec.size();n++) { // for each segment
EventList & el=*evec[n];
accel=el.type()==EVL_Waveform; // Turn on acceleration if this is a waveform.
square_plot=m_square_plot;
if (accel || num_points>500) { // Don't square plot if too many points or waveform
square_plot=false;
}
int siz=evec[n]->count();
if (siz<=1) continue; // Don't bother drawing 1 point or less.
QPointD * point=data->point[n];
x0=point[0].x();
xL=point[siz-1].x();
x0=el.time(0);
xL=el.time(siz-1);
if (maxx<x0) continue;
if (xL<minx) continue;
if (x0>xL) {
if (siz==2) { // this happens on CPAP
/*if (siz==2) { // this happens on CPAP
QPointD t=point[0];
point[0]=point[siz-1];
point[siz-1]=t;
x0=point[0].x();
} else {
} else { */
qDebug() << "Reversed order sample fed to gLineChart - ignored.";
continue;
//assert(x1<x2);
}
//}
}
done=false;
first=true;
dp=0;
x1=point[1].x();
// if (accel) {
sr=x1-x0; // Time distance between samples
if (accel) {
x1=el.time(1);
sr=el.rate(); // Time distance between samples
if (sr<=0) {
qWarning() << "qLineChart::Plot() assert(sr>0)";
return;
continue;
}
//assert(sr>0);
// double qx=xL-x0; // Full time range of this segment
//double gx=xx/qx; // ratio of how much of the whole data set this represents
//double segwidth=width*gx;
double XR=xx/sr;
double Z1=MAX(x0,minx);
double Z2=MIN(xL,maxx);
@ -169,18 +197,19 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
accel=false;
}
}
// Prepare the min max y values if we still are accelerating this plot
if (accel) {
for (int i=0;i<width;i++) {
m_drawlist[i].setX(height);
m_drawlist[i].setY(0);
}
minz=width;
maxz=0;
}
total_visible+=visible_points;
} else {
sam=1;
}
int minz=width,maxz=0;
// Technically shouldn't never ever get fed reverse data.
// these calculations over estimate
// The Z? values are much more accurate
@ -188,7 +217,11 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
idx=0;
idxend=0;
np=0;
if (m_accelerate) {
if (el.type()==EVL_Waveform) {
// We can skip data previous to minx if this is a waveform
if (minx>x1) {
double j=minx-x0; // == starting min of first sample in this segment
idx=floor(j/sr);
@ -207,101 +240,169 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
np=siz;
}
bool watch_verts_carefully=false;
//bool watch_verts_carefully=false;
// better to do it here than in the main loop.
np <<= 2;
if (!accel && square_plot)
if (square_plot)
np <<= 1; // double it again
if (np>=maxverts) {
watch_verts_carefully=true;
// watch_verts_carefully=true;
//assert(np<maxverts);
}
int xst=start_px+1;
int yst=start_py+1;
//int done2=0;
qint64 time;
EventDataType data;
EventDataType gain=el.gain();
EventDataType nmult=ymult*gain;
EventDataType ymin=miny/gain;
const vector<EventStoreType> & dat=el.getData();
const vector<qint64> & tim=el.getTime();
bool firstpx=true;
int done2=0;
if (el.type()==EVL_Waveform) { // Waveform Plot
time=el.time(idx);
qint64 rate=sr*sam;
if (accel) {
for (int i=idx;i<siz;i+=sam) {
time+=rate;
//time=el.time(i);
if (time < minx)
continue; // Skip stuff before the start of our data window
if (first && point[i].x() < minx) continue; // Skip stuff before the start of our data window
//data=el.data(i);
data=dat[i];//*gain;
px=((time - minx) * xmult); // Scale the time scale X to pixel scale X
py=((data - ymin) * nmult); // Same for Y scale
if (first) {
first=false;
if (i>=sam) i-=sam; // Start with the previous sample (which will be in clipping area)
}
px=1+((point[i].x() - minx) * xmult); // Scale the time scale X to pixel scale X
if (!accel) {
py=1+((point[i].y() - miny) * ymult); // Same for Y scale
if (firstpx) {
firstpx=false;
} else {
if (m_square_plot) {
vertarray[vertcnt++]=lastpx;
vertarray[vertcnt++]=lastpy;
vertarray[vertcnt++]=start_px+px;
vertarray[vertcnt++]=lastpy;
vertarray[vertcnt++]=start_px+px;
vertarray[vertcnt++]=lastpy;
} else {
vertarray[vertcnt++]=lastpx;
vertarray[vertcnt++]=lastpy;
}
vertarray[vertcnt++]=start_px+px;
vertarray[vertcnt++]=start_py+py;
if (vertcnt>=maxverts) break;
//#if defined(EXTRA_ASSERTS)
//assert(vertcnt<maxverts);
//#endif
}
lastpx=start_px+px;
lastpy=start_py+py;
//if (lastpx>start_px+width) done=true;
} else {
// In accel mode, each pixel has a min/max Y value.
// m_drawlist's index is the pixel index for the X pixel axis.
//float zz=(maxy-miny)/2.0; // centreline
int y1=1+(point[i].y()-miny)*ymult;
int z=floor(px); // Hmmm... round may screw this up.
if (z<minz) minz=z; // minz=First pixel
if (z>maxz) maxz=z; // maxz=Last pixel
// Update the Y pixel bounds.
if (y1<m_drawlist[z].x()) m_drawlist[z].setX(y1);
if (y1>m_drawlist[z].y()) m_drawlist[z].setY(y1);
//if (z>width) done=true;
if (py<m_drawlist[z].x()) m_drawlist[z].setX(py);
if (py>m_drawlist[z].y()) m_drawlist[z].setY(py);
if (time > maxx) {
done=true; // Let this iteration finish.. (This point will be in far clipping)
break;
}
}
// Plot compressed accelerated vertex list
for (int i=minz;i<maxz;i++) {
vertarray[vertcnt++]=xst+i;
vertarray[vertcnt++]=yst+m_drawlist[i].x();
vertarray[vertcnt++]=xst+i;
vertarray[vertcnt++]=yst+m_drawlist[i].y();
if (vertcnt>=maxverts) break;
}
} else { // Zoomed in Waveform
for (int i=idx;i<siz;i+=sam,time+=rate) {
if (time < minx)
continue; // Skip stuff before the start of our data window
data=dat[i];//el.data(i);
px=xst+((time - minx) * xmult); // Scale the time scale X to pixel scale X
py=yst+((data - ymin) * nmult); // Same for Y scale, with precomputed gain
if (firstpx) {
lastpx=px;
lastpy=py;
firstpx=false;
continue;
}
vertarray[vertcnt++]=lastpx;
vertarray[vertcnt++]=lastpy;
vertarray[vertcnt++]=px;
vertarray[vertcnt++]=py;
if (vertcnt>=maxverts) {
done=true;
break;
}
if (time > maxx) {
//done=true; // Let this iteration finish.. (This point will be in far clipping)
break;
}
lastpx=px;
lastpy=py;
}
}
} else { // Standard events/zoomed in Plot
for (int i=idx;i<siz;i+=sam) {
time=tim[i]; //el.time(i);
if (first) {
if (time < minx) continue; // Skip stuff before the start of our data window
first=false;
if (i>=sam) i-=sam; // Start with the previous sample (which will be in clipping area)
}
data=dat[i]*gain; //
//data=el.data(i); // raw access is faster
px=xst+((time - minx) * xmult); // Scale the time scale X to pixel scale X
//py=yst+((data - ymin) * nmult); // Same for Y scale with precomputed gain
py=yst+((data - miny) * ymult); // Same for Y scale with precomputed gain
if (firstpx) {
firstpx=false;
} else {
if (m_square_plot) {
vertarray[vertcnt++]=lastpx;
vertarray[vertcnt++]=lastpy;
vertarray[vertcnt++]=px;
vertarray[vertcnt++]=lastpy;
vertarray[vertcnt++]=px;
vertarray[vertcnt++]=lastpy;
} else {
vertarray[vertcnt++]=lastpx;
vertarray[vertcnt++]=lastpy;
}
vertarray[vertcnt++]=px;
vertarray[vertcnt++]=py;
if (vertcnt>=maxverts) {
done=true;
break;
}
}
lastpx=px;
lastpy=py;
//if (lastpx>start_px+width) done=true;
if (time > maxx) {
//done=true; // Let this iteration finish.. (This point will be in far clipping)
break;
}
}
}
if (point[i].x() > maxx) done=true; // Let this iteration finish.. (This point will be in far clipping)
if (done) break;
}
if (accel) {
dp=0;
// Plot compressed accelerated vertex list
for (int i=minz;i<maxz;i++) {
vertarray[vertcnt++]=start_px+i+1;
vertarray[vertcnt++]=start_py+m_drawlist[i].x();
vertarray[vertcnt++]=start_px+i+1;
vertarray[vertcnt++]=start_py+m_drawlist[i].y();
if (vertcnt>=maxverts) break;
//#if defined(EXTRA_ASSERTS)
//assert(vertcnt<maxverts);
//#endif
}
}
}
if (!total_points) { // No Data?
if (m_report_empty) {
QString msg="No Waveform Available";
float x,y;
GetTextExtent(msg,x,y,bigfont);
DrawText(msg,start_px+(width/2.0)-(x/2.0),scry-w.GetBottomMargin()-height/2.0+y/2.0,0,Qt::gray,bigfont);
}
} else {
/*QString b;
long j=vertcnt/2;
@ -314,17 +415,15 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
glColor4ub(col.red(),col.green(),col.blue(),255);
// Crop to inside the margins.
glScissor(w.GetLeftMargin(),w.GetBottomMargin(),width,height);
glScissor(w.GetLeftMargin(),w.GetBottomMargin(),width,height+2);
glEnable(GL_SCISSOR_TEST);
glDisable(GL_TEXTURE_2D);
glDisable(GL_DEPTH_TEST);
//glAlphaFunc(GL_LESS,0.8);
glLineWidth (1);
bool antialias=pref["UseAntiAliasing"].toBool();
if (antialias) {
glEnable(GL_BLEND);
glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA); //SRC_ALPHA,GL_ONE_MINUS_SRC_ALPHA);
//glBlendFunc(GL_ONE, GL_SRC_ALPHA);
glEnable(GL_LINE_SMOOTH);
glHint(GL_LINE_SMOOTH_HINT, GL_NICEST);
@ -340,5 +439,6 @@ void gLineChart::Plot(gGraphWindow & w,float scrx,float scry)
glDisable(GL_BLEND);
}
glDisable(GL_SCISSOR_TEST);
}
}

View File

@ -7,32 +7,28 @@
#ifndef GLINECHART_H
#define GLINECHART_H
#include <vector>
#include "SleepLib/event.h"
#include "SleepLib/day.h"
#include "graphwindow.h"
#include "graphlayer.h"
class gLineChart:public gLayer
{
public:
gLineChart(gPointData *d=NULL,const QColor col=QColor("black"),int dlsize=4096,bool accelerate=false,bool _hide_axes=false,bool _square_plot=false);
gLineChart(MachineCode code,const QColor col=QColor("black"), bool _square_plot=false);
virtual ~gLineChart();
virtual void Plot(gGraphWindow & w,float scrx,float scry);
void SetSquarePlot(bool b) { m_square_plot=b; };
bool GetSquarePlot() { return m_square_plot; };
void ReportEmpty(bool b) { m_report_empty=b; };
bool GetReportEmpty() { return m_report_empty; };
void SetSquarePlot(bool b) { m_square_plot=b; }
bool GetSquarePlot() { return m_square_plot; }
void ReportEmpty(bool b) { m_report_empty=b; }
bool GetReportEmpty() { return m_report_empty; }
protected:
bool m_accelerate;
int m_drawlist_size;
protected:
bool m_report_empty;
QPointD *m_drawlist;
bool m_hide_axes;
bool m_square_plot;
//gYAxis * Yaxis;
//gFooBar *foobar;
};
#endif // GLINECHART_H

View File

@ -8,8 +8,8 @@
#include "SleepLib/profiles.h"
#include "gLineOverlay.h"
gLineOverlayBar::gLineOverlayBar(gPointData *d,QColor col,QString _label,LO_Type _lot)
:gLayer(d),label(_label),lo_type(_lot)
gLineOverlayBar::gLineOverlayBar(MachineCode code,QColor col,QString _label,LO_Type _lot)
:gLayer(code),label(_label),lo_type(_lot)
{
color.clear();
color.push_back(col);
@ -17,31 +17,11 @@ gLineOverlayBar::gLineOverlayBar(gPointData *d,QColor col,QString _label,LO_Type
gLineOverlayBar::~gLineOverlayBar()
{
}
//nov = number of vertex
//r = radius
void Dot(int nov, float r)
{
if (nov < 4) nov = 4;
if (nov > 360) nov = 360;
float angle = (360/nov)*(3.142159/180);
float x[360] = {0};
float y[360] = {0};
for (int i = 0; i < nov; i++){
x[i] = cosf(r*cosf(i*angle));
y[i] = sinf(r*sinf(i*angle));
glBegin(GL_POLYGON);
for (int i = 0; i < nov; i++){
glVertex2f(x[i],y[i]);
}
glEnd();
}
//render to texture and map to GL_POINT_SPRITE
}
void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry)
{
if (!m_visible) return;
if (!data) return;
if (!data->IsReady()) return;
if (!m_day) return;
//int start_px=w.GetLeftMargin();
int start_py=w.GetBottomMargin();
@ -53,7 +33,7 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry)
float x1,x2;
float x,y;//,descent,leading;
float x,y;
// Crop to inside the margins.
glScissor(w.GetLeftMargin(),w.GetBottomMargin(),width,height);
@ -72,19 +52,30 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry)
float bottom=start_py+25, top=start_py+height-25;
QColor & col=color[0];
for (int n=0;n<data->VC();n++) {
qint64 X;
qint64 Y;
for (vector<Session *>::iterator s=m_day->begin();s!=m_day->end(); s++) {
if ((*s)->eventlist.find(m_code)==(*s)->eventlist.end()) continue;
EventList & el=*((*s)->eventlist[m_code][0]);
// bool done=false;
for (int i=0;i<data->np[n];i++) {
QPointD & rp=data->point[n][i];
//float X=rp.x();
//float Y=rp.y();
if (rp.y() < w.min_x) continue;
if (rp.x() > w.max_x) break;
for (int i=0;i<el.count();i++) {
X=el.time(i);
if (lo_type==LOT_Span) {
Y=X-(qint64(el.raw(i))*1000.0L); // duration
x1=w.x2p(rp.x());
if (rp.x()!=rp.y()) {
x2=w.x2p(rp.y());
if (X < w.min_x) continue;
if (Y > w.max_x) break;
} else {
if (X < w.min_x) continue;
if (X > w.max_x) break;
}
x1=w.x2p(X);
if (lo_type==LOT_Span) {
x2=w.x2p(Y);
//double w1=x2-x1;
quadarray[quadcnt++]=x1;
quadarray[quadcnt++]=start_py;
@ -94,11 +85,10 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry)
quadarray[quadcnt++]=start_py+height;
quadarray[quadcnt++]=x2;
quadarray[quadcnt++]=start_py;
} else {
if (lo_type==LOT_Dot) {
} else if (lo_type==LOT_Dot) {
//if (pref["AlwaysShowOverlayBars"].toBool()) {
if (pref["AlwaysShowOverlayBars"].toBool() || (xx<(3600.0/86400.0))) {
if (pref["AlwaysShowOverlayBars"].toBool() || (xx<3600000.0)) {
// show the fat dots in the middle
pointarray[pointcnt++]=x1;
pointarray[pointcnt++]=w.y2p(20);
@ -111,7 +101,7 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry)
}
} else if (lo_type==LOT_Bar) {
int z=start_py+height;
if (pref["AlwaysShowOverlayBars"].toBool() || (xx<(3600.0/86400.0))) {
if (pref["AlwaysShowOverlayBars"].toBool() || (xx<3600000)) {
z=top;
pointarray[pointcnt++]=x1;
@ -126,7 +116,7 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry)
vertarray[vertcnt++]=x1;
vertarray[vertcnt++]=z-12;
}
if (xx<(1800.0/86400.0)) {
if (xx<(1800000)) {
GetTextExtent(label,x,y);
DrawText(label,x1-(x/2),scry-(start_py+height-30+y));
//w.renderText(x1-(x/2),scry-(start_py+height-30+y),label);
@ -135,12 +125,9 @@ void gLineOverlayBar::Plot(gGraphWindow & w,float scrx,float scry)
}
}
if ((vertcnt>=maxverts) || (quadcnt>=maxverts) || (pointcnt>=maxverts)) break;
}
}
//assert (vertcnt<maxverts);
//assert (quadcnt<maxverts);
//assert (pointcnt<maxverts);
glColor4ub(col.red(),col.green(),col.blue(),col.alpha());
if (quadcnt>0) {
glEnableClientState(GL_VERTEX_ARRAY);

View File

@ -1,8 +1,8 @@
/********************************************************************
/*
gLineOverlayBar Header
Copyright (c)2011 Mark Watkins <jedimark@users.sourceforge.net>
License: GPL
*********************************************************************/
*/
#ifndef GLINEOVERLAY_H
#define GLINEOVERLAY_H
@ -10,15 +10,17 @@
#include "graphlayer.h"
#include "graphdata.h"
enum LO_Type { LOT_Bar, LOT_Dot };
enum LO_Type { LOT_Bar, LOT_Span, LOT_Dot };
class gLineOverlayBar:public gLayer
{
public:
gLineOverlayBar(gPointData *d=NULL,QColor col=QColor("black"),QString _label="",LO_Type _lot=LOT_Bar);
gLineOverlayBar(MachineCode code,QColor col=QColor("black"),QString _label="",LO_Type _lot=LOT_Bar);
virtual ~gLineOverlayBar();
virtual void Plot(gGraphWindow & w,float scrx,float scry);
virtual EventDataType Miny() { return 0; }
virtual EventDataType Maxy() { return 0; }
virtual bool isEmpty() { return true; }
protected:
QString label;
LO_Type lo_type;

View File

@ -27,8 +27,8 @@ const QString & gTimeYAxis::Format(double v)
};
gSessionTime::gSessionTime(gPointData *d,QColor col,Qt::Orientation o)
:gLayer(d),m_orientation(o)
gSessionTime::gSessionTime(MachineCode code,QColor col,Qt::Orientation o)
:gLayer(code),m_orientation(o)
{
color.clear();
color.push_back(col);
@ -43,7 +43,7 @@ gSessionTime::~gSessionTime()
void gSessionTime::Plot(gGraphWindow & w,float scrx,float scry)
{
if (!m_visible) return;
if (!data) return;
/*if (!data) return;
if (!data->IsReady()) return;
int start_px=w.GetLeftMargin();
@ -157,5 +157,5 @@ void gSessionTime::Plot(gGraphWindow & w,float scrx,float scry)
glVertex2f (start_px, start_py+height+1);
glVertex2f (start_px,start_py);
glVertex2f (start_px+width, start_py);
glEnd ();
glEnd (); */
}

View File

@ -23,7 +23,7 @@ public:
class gSessionTime:public gLayer
{
public:
gSessionTime(gPointData *d=NULL,QColor col=QColor("blue"),Qt::Orientation o=Qt::Horizontal);
gSessionTime(MachineCode=MC_UNKNOWN,QColor col=QColor("blue"),Qt::Orientation o=Qt::Horizontal);
virtual ~gSessionTime();
virtual void Plot(gGraphWindow & w,float scrx,float scry);
@ -31,10 +31,10 @@ class gSessionTime:public gLayer
protected:
Qt::Orientation m_orientation;
virtual const QString & FormatX(double v) { static QString t; QDateTime d; d=d.fromMSecsSinceEpoch(v*86400000.0); t=d.toString("MMM dd"); return t; };
virtual const QString & FormatX(double v) { static QString t; QDateTime d; d=d.fromMSecsSinceEpoch(v*86400000.0); t=d.toString("MMM dd"); return t; }
//virtual const wxString & FormatX(double v) { static wxString t; wxDateTime d; d.Set(vi*86400000.0); t=d.Format(wxT("HH:mm")); return t; };
//virtual const wxString & FormatX(double v) { static wxString t; t=wxString::Format(wxT("%.1f"),v); return t; };
virtual const QString & FormatY(double v) { static QString t; t.sprintf("%.1f",v); return t; };
virtual const QString & FormatY(double v) { static QString t; t.sprintf("%.1f",v); return t; }
gXAxis *Xaxis;
};

View File

@ -7,7 +7,7 @@
#include "gTitle.h"
gTitle::gTitle(const QString & _title,QColor color,QFont font)
:gLayer(NULL),m_title(_title),m_color(color),m_font(font)
:gLayer(MC_UNKNOWN),m_title(_title),m_color(color),m_font(font)
{
}
gTitle::~gTitle()
@ -16,10 +16,11 @@ gTitle::~gTitle()
void gTitle::Plot(gGraphWindow & w,float scrx,float scry)
{
if (!m_visible) return;
scrx=scrx;
float width,height;
GetTextExtent(m_title,width,height);
int xp=(height/2)+20;
int xp=(height/2)+15;
//if (m_alignment==wxALIGN_RIGHT) xp=scrx-4-height;
DrawText(m_title,xp,scry-(w.GetBottomMargin()+((scry-w.GetBottomMargin())/2.0)),90.0,m_color,&m_font);

View File

@ -9,7 +9,7 @@
#include "gXAxis.h"
gXAxis::gXAxis(QColor col)
:gLayer(NULL)
:gLayer(MC_UNKNOWN)
{
color.clear();
color.push_back(col);
@ -31,8 +31,8 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
float width=scrx-(w.GetLeftMargin()+w.GetRightMargin());
// float height=scry-(w.GetTopMargin()+w.GetBottomMargin());
double minx;
double maxx;
qint64 minx;
qint64 maxx;
if (w.BlockZoom()) {
minx=w.rmin_x;
maxx=w.rmax_x;
@ -47,7 +47,7 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
double xmult=width/xx;
QString fd;
if (xx<1.5) {
if (xx<86400000L) {
fd="00:00:00:0000";
} else {
fd="XXX";
@ -70,9 +70,9 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
bool show_time=true;
double min_tick;
if (xx<1.5) {
int rounding[16]={12,24,48,72,96,144,288,720,1440,2880,5760,8640,17280,86400,172800,345600}; // time rounding
if (xx<86400000) {
//double rounding[16]={12,24,48,72,96,144,288,720,1440,2880,5760,8640,17280,86400,172800,345600}; // time rounding
double rounding[16]={7200000,3600000,1800000,1200000,900000,600000,300000,120000,60000,45000,30000,15000,10000,5000,2000,1000};
int ri;
for (ri=0;ri<16;ri++) {
st=round(st2*rounding[ri])/rounding[ri];
@ -80,11 +80,11 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
q=xx/min_tick; // number of ticks that fits in range
if (q<=jj) break; // compared to number of ticks that fit on screen.
}
if (ri>8) show_seconds=true;
if (ri>=14) show_milliseconds=true;
if (min_tick<60000) show_seconds=true;
if (min_tick<10000) show_milliseconds=true;
if (min_tick<=0.25/86400.0)
min_tick=0.25/86400;
if (min_tick<=1000)
min_tick=1000;
} else { // Day ticks..
show_time=false;
st=st2;
@ -101,10 +101,10 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
}
double st3=st;
while (st3>minx) {
st3-=min_tick/10.0;
}
st3+=min_tick/10.0;
//while (st3>minx) {
// st3-=min_tick/10.0;
//}
//st3+=min_tick/10.0;
py=w.GetBottomMargin();
@ -131,9 +131,9 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
}
while (st<minx) {
st+=min_tick; //10.0; // mucking with this changes the scrollyness of the ticker.
}
//while (st<minx) {
// st+=min_tick/10.0; // mucking with this changes the scrollyness of the ticker.
//}
int hour,minute,second,millisecond;
QDateTime d;
@ -144,8 +144,9 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
//const double extra=min_tick/10.0;
const double extra=0;
for (double i=st; i<=maxx+extra; i+=min_tick) {
d=QDateTime::fromMSecsSinceEpoch(i*86400000.0);
d=QDateTime::fromMSecsSinceEpoch(i);
if (show_time) {
minute=d.time().minute();
@ -177,17 +178,14 @@ void gXAxis::Plot(gGraphWindow & w,float scrx,float scry)
}
GetTextExtent(fd,x,y);
//glColor3ub(0,0,0);
if (!show_time) {
DrawText(fd, px+y, scry-(py-(x/2)-8), 90.0);
//w.renderText(px-(y/2)+2, scry-(py-(x/2)-20), 90.0,fd);
} else {
DrawText(fd, px-(x/2), scry-(py-8-y));
//w.renderText(px-(x/2), scry-(py-(y/2)-20), fd);
}
}
// Draw the little ticks.
// Draw the little ticks.
if (vertcnt>=maxverts) {
qWarning() << "maxverts exceeded in gYAxis::Plot()";
return;

View File

@ -9,7 +9,7 @@
#include "gYAxis.h"
gYAxis::gYAxis(QColor col)
:gLayer(NULL)
:gLayer(MC_UNKNOWN)
{
color.clear();
color.push_back(col);
@ -30,8 +30,45 @@ void gYAxis::Plot(gGraphWindow &w,float scrx,float scry)
double miny=w.min_y;
double maxy=w.max_y;
if (maxy==miny)
double dy=maxy-miny;
if (dy<=0)
return;
int m;
if (maxy>500) {
m=ceil(maxy/100.0);
maxy=m*100;
m=floor(miny/100.0);
miny=m*100;
} else if (maxy>150) {
m=ceil(maxy/50.0);
maxy=m*50;
m=floor(miny/50.0);
miny=m*50;
} else if (maxy>80) {
m=ceil(maxy/20.0);
maxy=m*20;
m=floor(miny/20.0);
miny=m*20;
} else if (maxy>30) {
m=ceil(maxy/10.0);
maxy=m*10;
m=floor(miny/10.0);
miny=m*10;
} else if (maxy>5) {
m=ceil(maxy/5.0);
maxy=m*5;
m=floor(miny/5.0);
miny=m*5;
} else {
maxy=ceil(maxy);
if (maxy<1) maxy=1;
miny=floor(miny);
if (miny<1) miny=0;
}
//if ((w.max_x-w.min_x)==0)
// return;

View File

@ -6,6 +6,7 @@
#include <QApplication>
#include <QFontMetrics>
#include <QMessageBox>
#include <QDebug>
#include <math.h>
#include "glcommon.h"
@ -63,9 +64,8 @@ inline void RDrawText(QPainter & painter, QString text, int x, int y, float ang
//int a=fm.overlinePos(); //ascent();
//LinedRoundedRectangle(x,wid.GetScrY()-y,w,h,0,1,QColor("black"));
if (!font) {
qDebug() << "Font Problem. Forgot to call GraphInit() ?";
abort();
return;
QMessageBox::critical(NULL,"Critical Error","Font Problem. Forgot to call GraphInit()? Have to abort");
exit(-1);
}
// glEnable(GL_TEXTURE_2D);

View File

@ -1,8 +1,8 @@
#include <math.h>
#include "gpiechart.h"
gPieChart::gPieChart(gPointData *d,QColor col)
:gLayer(d)
gPieChart::gPieChart(MachineCode code,QColor col)
:gLayer(code)
{
color.clear();
color.push_back(col);
@ -14,7 +14,7 @@ gPieChart::~gPieChart()
void gPieChart::Plot(gGraphWindow & w,float scrx,float scry)
{
if (!m_visible) return;
if (!data) return;
/*if (!data) return;
if (!data->IsReady()) return;
int start_px=w.GetLeftMargin();
@ -83,7 +83,7 @@ void gPieChart::Plot(gGraphWindow & w,float scrx,float scry)
sum=q;
}
glDisable(GL_POLYGON_SMOOTH);
glDisable(GL_BLEND);
glDisable(GL_BLEND); */
//glDisable(GL_DEPTH_TEST);
//glDisable(GL_TEXTURE_2D);
}

View File

@ -5,11 +5,11 @@
class gPieChart : public gLayer
{
public:
gPieChart(gPointData *d,QColor col=Qt::black);
gPieChart(MachineCode code=MC_UNKNOWN,QColor col=Qt::black);
virtual ~gPieChart();
virtual void Plot(gGraphWindow & w,float scrx,float scry);
void AddName(QString name) { m_names.push_back(name); };
void AddName(QString name) { m_names.push_back(name); }
protected:
vector<QString> m_names;

View File

@ -5,7 +5,7 @@
*********************************************************************/
#include "graphdata.h"
/*
gGraphData::gGraphData(int mp,gDataType t)
:vc(0),type(t),max_points(mp)
{
@ -99,3 +99,4 @@ double gPointData::CalcMaxY()
}
return max;
}
*/

View File

@ -11,7 +11,7 @@
#include "SleepLib/day.h"
#include <list>
using namespace std;
enum gDataType { gDT_Point, gDT_Point3D, gDT_Stacked, gDT_Segmented };
/*enum gDataType { gDT_Point, gDT_Point3D, gDT_Stacked, gDT_Segmented };
class gLayer;
@ -113,5 +113,5 @@ public:
vector<QPointD *> point;
};
*/
#endif // GRAPHDATA_H

View File

@ -8,7 +8,7 @@
#include <QDebug>
#include "graphdata_custom.h"
/*
WaveData::WaveData(MachineCode _code, int _size)
:gPointData(_size),code(_code)
{
@ -336,14 +336,14 @@ void FlagData::Reload(Day *day)
done=true;
break;
}
/*if (first) {
if (first) {
min_y=v1;
first=false;
} else {
if (v1<min_x) min_x=v1;
}
if (v2>max_x) max_x=v2; */
if (v2>max_x) max_x=v2;
}
if (done) break;
}
@ -364,20 +364,20 @@ void FlagData::Reload(Day *day)
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; */
//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()
void SessionTimes::ResetDateRange()
{
if (profile->LastDay().isValid()) {
QDateTime tmp;
@ -413,7 +413,6 @@ void SessionTimes::SetDateRange(QDate start,QDate end)
(*i)->DataChanged(this);
} // Do nothing else.. Callers responsibility to Refresh window.
}
*/
void SessionTimes::Reload(Day *day)
{
@ -650,3 +649,4 @@ double UsageHistoryData::Calc(Day *day)
return 0;
}
*/

View File

@ -13,6 +13,7 @@
#include "SleepLib/machine_common.h"
#include "graphdata.h"
/*
class FlagData:public gPointData
{
public:
@ -127,5 +128,5 @@ protected:
T_UHD uhd;
};
*/
#endif // GRAPHDATA_CUSTOM_H

View File

@ -6,16 +6,16 @@
#include "graphlayer.h"
gLayer::gLayer(gPointData *d,QString title)
:m_title(title),data(d)
gLayer::gLayer(MachineCode code,QString title)
:m_code(code),m_title(title)
{
if (data) {
data->AddLayer(this);
}
m_visible = true;
m_movable = false;
color.push_back(QColor("red"));
color.push_back(QColor("green"));
m_day=NULL;
m_miny=m_maxy=0;
m_minx=m_maxx=0;
}
gLayer::~gLayer()
@ -23,56 +23,47 @@ gLayer::~gLayer()
}
//void gLayer::Plot(gGraphWindow & w,float scrx,float scry)
//{
//}
void gLayer::DataChanged(gGraphData *src)
void gLayer::SetDay(Day * d)
{
for (list<gGraphWindow *>::iterator i=m_graph.begin();i!=m_graph.end();i++) {
if (src) {
(*i)->DataChanged(this);
} else {
(*i)->DataChanged(NULL);
}
}
m_day=d;
if (!d) return;
m_minx=d->first(m_code);
m_maxx=d->last(m_code);
m_miny=d->min(m_code);
m_maxy=d->max(m_code);
}
// Notify signal sent from gGraphData.. pass on to the graph so it can que a refresh and update stuff.
void gLayer::SetData(gPointData * gd) { data=gd; };
gPointData * gLayer::GetData() { return data; };
double gLayer::MinX() { if (data) return data->MinX(); return 0;};
double gLayer::MaxX() { if (data) return data->MaxX(); return 0;};
double gLayer::MinY() { if (data) return data->MinY(); return 0;};
double gLayer::MaxY() { if (data) return data->MaxY(); return 0;};
double gLayer::RealMinX() { if (data) return data->RealMinX(); return 0;};
double gLayer::RealMaxX() { if (data) return data->RealMaxX(); return 0;};
double gLayer::RealMinY() { if (data) return data->RealMinY(); return 0;};
double gLayer::RealMaxY() { if (data) return data->RealMaxY(); return 0;};
bool gLayer::isEmpty()
{
if (m_day && (m_day->count(m_code)!=0))
return false;
return true;
}
void gLayer::SetMinX(double v) { if (data) data->SetMinX(v); };
void gLayer::SetMaxX(double v) { if (data) data->SetMaxX(v); };
void gLayer::SetMinY(double v) { if (data) data->SetMinY(v); };
void gLayer::SetMaxY(double v) { if (data) data->SetMaxY(v); };
void gLayer::NotifyGraphWindow(gGraphWindow *g) { m_graph.push_back(g); };
bool gLayer::isEmpty() { if (!data) return false; return data->isEmpty(); };
gLayerGroup::gLayerGroup()
gLayerGroup::gLayerGroup():gLayer(MC_UNKNOWN)
{
}
gLayerGroup::~gLayerGroup()
{
}
//void gLayerGroup::DataChanged(gGraphData *src);
void gLayerGroup::NotifyGraphWindow(gGraphWindow *g)
bool gLayerGroup::isEmpty()
{
bool empty=true;
for (unsigned i=0;i<layers.size();i++) {
if (layers[i]->isEmpty()) {
empty=false;
break;
}
}
return empty;
}
void gLayerGroup::SetDay(Day * d)
{
for (unsigned i=0;i<layers.size();i++) {
layers[i]->NotifyGraphWindow(g);
layers[i]->SetDay(d);
}
m_day=d;
}
void gLayerGroup::AddLayer(gLayer *l)
@ -80,91 +71,65 @@ void gLayerGroup::AddLayer(gLayer *l)
layers.push_back(l);
}
double gLayerGroup::MinX()
qint64 gLayerGroup::Minx()
{
bool first=true;
double m=0;
qint64 m=0,t;
for (unsigned i=0;i<layers.size();i++) {
t=layers[i]->Minx();
if (!t) continue;
if (first) {
m=layers[i]->MinX();
m=t;
first=false;
} else
if (m>layers[i]->MinX()) m=layers[i]->MinX();
if (m>t) m=t;
}
return m;
}
double gLayerGroup::MaxX()
qint64 gLayerGroup::Maxx()
{
bool first=true;
double m=0;
qint64 m=0,t;
for (unsigned i=0;i<layers.size();i++) {
t=layers[i]->Maxx();
if (!t) continue;
if (first) {
m=layers[i]->MaxX();
m=t;
first=false;
} else
if (m<layers[i]->MaxX()) m=layers[i]->MaxX();
if (m<t) m=t;
}
return m;
}
double gLayerGroup::MinY()
EventDataType gLayerGroup::Miny()
{
bool first=true;
EventDataType m=0,t;
for (unsigned i=0;i<layers.size();i++) {
t=layers[i]->Miny();
if (t==layers[i]->Minx()) continue;
if (first) {
m=t;
first=false;
} else {
if (m>t) m=t;
}
}
return m;
}
double gLayerGroup::MaxY()
EventDataType gLayerGroup::Maxy()
{
bool first=true;
EventDataType m=0,t;
for (unsigned i=0;i<layers.size();i++) {
t=layers[i]->Maxy();
if (t==layers[i]->Miny()) continue;
if (first) {
m=t;
first=false;
} else
if (m<t) m=t;
}
return m;
}
double gLayerGroup::RealMinX()
{
bool first=true;
double m=0;
for (unsigned i=0;i<layers.size();i++) {
if (first) {
m=layers[i]->RealMinX();
first=false;
} else
if (m>layers[i]->RealMinX()) m=layers[i]->RealMinX();
}
return m;
}
double gLayerGroup::RealMaxX()
{
bool first=true;
double m=0;
for (unsigned i=0;i<layers.size();i++) {
if (first) {
m=layers[i]->RealMaxX();
first=false;
} else
if (m>layers[i]->RealMaxX()) m=layers[i]->RealMaxX();
}
return m;
}
double gLayerGroup::RealMinY()
{
return 0;
}
double gLayerGroup::RealMaxY()
{
return 0;
}
void gLayerGroup::SetMinX(double v)
{
for (unsigned i=0;i<layers.size();i++)
layers[i]->SetMinX(v);
}
void gLayerGroup::SetMaxX(double v)
{
for (unsigned i=0;i<layers.size();i++)
layers[i]->SetMaxX(v);
}
void gLayerGroup::SetMinY(double v)
{
for (unsigned i=0;i<layers.size();i++)
layers[i]->SetMinY(v);
}
void gLayerGroup::SetMaxY(double v)
{
for (unsigned i=0;i<layers.size();i++)
layers[i]->SetMaxY(v);
}

View File

@ -8,6 +8,7 @@
#define GRAPHLAYER_H
#include <QString>
#include "SleepLib/day.h"
#include "graphwindow.h"
#include "graphdata.h"
@ -18,43 +19,31 @@ class gPointData;
class gLayer
{
public:
gLayer(gPointData *g=NULL,QString title="");
gLayer(MachineCode code=MC_UNKNOWN,QString title="");
virtual ~gLayer();
virtual void Plot(gGraphWindow & w,float scrx,float scry)=0;
vector<QColor> color;
virtual void SetData(gPointData * gd);;
virtual gPointData * GetData();;
virtual void SetDay(Day * d);
void SetCode(MachineCode c) { m_code=c; }
virtual qint64 Minx() { if (m_day) return m_day->first(); return m_minx; }
virtual qint64 Maxx() { if (m_day) return m_day->last(); return m_maxx; }
virtual EventDataType Miny() { return m_miny; }
virtual EventDataType Maxy() { return m_maxy; }
virtual void DataChanged(gGraphData *src);
virtual double MinX();
virtual double MaxX();
virtual double MinY();
virtual double MaxY();
virtual double RealMinX();
virtual double RealMaxX();
virtual double RealMinY();
virtual double RealMaxY();
virtual void SetMinX(double v);
virtual void SetMaxX(double v);
virtual void SetMinY(double v);
virtual void SetMaxY(double v);
virtual void NotifyGraphWindow(gGraphWindow *g);
virtual void SetVisible(bool v) { m_visible=v; };
virtual bool IsVisible() { return m_visible; };
virtual void setVisible(bool v) { m_visible=v; }
virtual bool isVisible() { return m_visible; }
virtual bool isEmpty();
inline const MachineCode & code() { return m_code; }
protected:
bool m_visible;
bool m_movable;
QString m_title;
gPointData *data; // Data source
list<gGraphWindow *> m_graph; // notify list of graphs that attach this layer.
qint64 m_minx,m_maxx;
EventDataType m_miny,m_maxy;
Day *m_day;
MachineCode m_code;
QString m_title;
};
class gLayerGroup:public gLayer
@ -64,24 +53,12 @@ public:
virtual ~gLayerGroup();
virtual void AddLayer(gLayer *l);
//virtual void DataChanged(gGraphData *src);
virtual void NotifyGraphWindow(gGraphWindow *g);
virtual double MinX();
virtual double MaxX();
virtual double MinY();
virtual double MaxY();
virtual double RealMinX();
virtual double RealMaxX();
virtual double RealMinY();
virtual double RealMaxY();
virtual void SetMinX(double v);
virtual void SetMaxX(double v);
virtual void SetMinY(double v);
virtual void SetMaxY(double v);
virtual qint64 Minx();
virtual qint64 Maxx();
virtual EventDataType Miny();
virtual EventDataType Maxy();
virtual bool isEmpty();
virtual void SetDay(Day * d);
protected:
vector<gLayer *> layers;

View File

@ -10,7 +10,10 @@
#include <QMouseEvent>
#include "SleepLib/profiles.h"
#include "graphwindow.h"
#include "Graphs/gTitle.h"
#include "gTitle.h"
#include "gXAxis.h"
#include "gYAxis.h"
#include "gFooBar.h"
extern QLabel *qstatus2;
@ -38,6 +41,8 @@ gGraphWindow::gGraphWindow(QWidget *parent, const QString & title, QGLWidget * s
//setAcceptDrops(true);
setMouseTracking(true);
setFocusPolicy(Qt::StrongFocus);
rmin_x=rmax_x=0;
min_x=max_x=0;
}
gGraphWindow::gGraphWindow(QWidget *parent, const QString & title, QGLContext * context,Qt::WindowFlags f)
@ -72,9 +77,18 @@ gGraphWindow::~gGraphWindow()
layers.clear();
}
#include "gXAxis.h"
#include "gYAxis.h"
#include "gFooBar.h"
bool gGraphWindow::isEmpty()
{
bool empty=true;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if (!(*l)->isEmpty()) {
empty=false;
break;
}
}
return empty;
}
void gGraphWindow::AddLayer(gLayer *l) {
if (l) {
if (dynamic_cast<gXAxis *>(l)) {
@ -113,34 +127,31 @@ void gGraphWindow::AddLayer(gLayer *l) {
m_marginLeft+=gTitle::Margin;
gtitle=l;
}
l->NotifyGraphWindow(this);
//l->NotifyGraphWindow(this);
layers.push_back(l);
}
};
// Sets a new Min & Max X clipping, refreshing the graph and all it's layers.
void gGraphWindow::SetXBounds(double minx, double maxx)
void gGraphWindow::SetXBounds(qint64 minx, qint64 maxx)
{
//min_x=minx;
//max_x=maxx;
SetMinX(minx);
SetMaxX(maxx);
min_x=minx;
max_x=maxx;
updateGL();
}
void gGraphWindow::ResetXBounds()
void gGraphWindow::ResetBounds()
{
//min_x=minx;
//max_x=maxx;
SetMinX(RealMinX());
SetMaxX(RealMaxX());
// updateGL();
min_x=MinX();
max_x=MaxX();
min_y=MinY();
max_y=MaxY();
}
void gGraphWindow::ZoomXPixels(int x1, int x2)
{
double rx1=0,rx2=0;
qint64 rx1=0,rx2=0;
ZoomXPixels(x1,x2,rx1,rx2);
if (pref["LinkGraphMovement"].toBool()) {
for (list<gGraphWindow *>::iterator g=link_zoom.begin();g!=link_zoom.end();g++) {
@ -150,7 +161,7 @@ void gGraphWindow::ZoomXPixels(int x1, int x2)
SetXBounds(rx1,rx2);
}
void gGraphWindow::ZoomXPixels(int x1,int x2,double &rx1,double &rx2)
void gGraphWindow::ZoomXPixels(int x1,int x2,qint64 &rx1,qint64 &rx2)
{
x1-=GetLeftMargin();
x2-=GetLeftMargin();
@ -159,8 +170,8 @@ void gGraphWindow::ZoomXPixels(int x1,int x2,double &rx1,double &rx2)
if (x1>Width()) x1=Width();
if (x2>Width()) x2=Width();
double min;
double max;
qint64 min;
qint64 max;
if (!m_block_zoom) {
min=min_x;
max=max_x;
@ -175,7 +186,7 @@ void gGraphWindow::ZoomXPixels(int x1,int x2,double &rx1,double &rx2)
}
// Move x-axis by the amount of space represented by integer i Pixels (negative values moves backwards)
void gGraphWindow::MoveX(int i,double &min, double & max)
void gGraphWindow::MoveX(int i,qint64 &min, qint64 & max)
{
//if (i==0) return;
min=min_x;
@ -198,7 +209,7 @@ void gGraphWindow::MoveX(int i,double &min, double & max)
void gGraphWindow::MoveX(int i)
{
double min,max;
qint64 min,max;
MoveX(i,min,max);
/* for (list<gGraphWindow *>::iterator g=link_zoom.begin();g!=link_zoom.end();g++) {
@ -222,8 +233,8 @@ void gGraphWindow::ZoomX(double mult,int origin_px)
// apply zoom
// center on point found in step 1.
double min=min_x;
double max=max_x;
qint64 min=min_x;
qint64 max=max_x;
double hardspan=rmax_x-rmin_x;
double span=max-min;
@ -234,7 +245,7 @@ void gGraphWindow::ZoomX(double mult,int origin_px)
double q=span*mult;
if (q>hardspan) q=hardspan;
if (q<hardspan/400) q=hardspan/400;
if (q<hardspan/400.0) q=hardspan/400.0;
min=min+origin-(q*ww);
max=min+q;
@ -254,7 +265,7 @@ void gGraphWindow::ZoomX(double mult,int origin_px)
void gGraphWindow::updateSelectionTime()
{
double f;
f=max_x-min_x;
f=(max_x-min_x)/86400000.0;
int hours,minutes,seconds;
hours=int(f*24.0);
@ -322,8 +333,8 @@ void gGraphWindow::mouseMoveEvent(QMouseEvent * event)
double mx=double(x1)/double(width);
double rminx=RealMinX();
double rmaxx=RealMaxX();
qint64 rminx=rmin_x;
qint64 rmaxx=rmax_x;
double rx=rmaxx-rminx;
double qx=rx*mx;
@ -331,8 +342,8 @@ void gGraphWindow::mouseMoveEvent(QMouseEvent * event)
// qx is centerpoint of new zoom area.
double minx=MinX();
double dx=MaxX()-minx; // zoom rect width;
qint64 minx=min_x;
double dx=max_x-minx; // zoom rect width;
// Could smarten this up by remembering where the mouse was clicked on the foobar
@ -366,11 +377,9 @@ void gGraphWindow::mouseMoveEvent(QMouseEvent * event)
if (event->buttons() & Qt::RightButton) {
MoveX(x - m_mouseRClick.x());
m_mouseRClick.setX(x);
double min=MinX();
double max=MaxX();
if (pref["LinkGraphMovement"].toBool()) {
for (list<gGraphWindow *>::iterator g=link_zoom.begin();g!=link_zoom.end();g++) {
(*g)->SetXBounds(min,max);
(*g)->SetXBounds(min_x,max_x);
}
}
} else
@ -393,7 +402,7 @@ void gGraphWindow::mouseMoveEvent(QMouseEvent * event)
z=max_x-min_x;
}
double q=double(t2-t1)/width();
double f=(q*z)*24.0;
double f=((q*z)/3600000.0);
int hours,minutes,seconds;
hours=int(f);
minutes=int(f*60.0) % 60;
@ -462,11 +471,9 @@ void gGraphWindow::keyPressEvent(QKeyEvent * event)
}
if (moved) {
double min=MinX();
double max=MaxX();
if (pref["LinkGraphMovement"].toBool()) {
for (list<gGraphWindow *>::iterator g=link_zoom.begin();g!=link_zoom.end();g++) {
(*g)->SetXBounds(min,max);
(*g)->SetXBounds(min_x,max_x);
}
}
event->accept();
@ -499,10 +506,10 @@ void gGraphWindow::OnMouseRightDown(QMouseEvent * event)
// m_mouseRDown=true;
if (foobar && m_block_zoom && (((y>GetTopMargin())) && (y<m_scrY))) {
double rx=RealMaxX()-RealMinX();
double rx=rmax_x-rmin_x;
double qx=double(width)/rx;
double minx=MinX()-RealMinX();
double maxx=MaxX()-RealMinX();;
qint64 minx=min_x-rmin_x;
qint64 maxx=max_x-rmin_x;
int x1=(qx*minx);
int x2=(qx*maxx); // length in pixels
@ -574,10 +581,8 @@ void gGraphWindow::OnMouseRightRelease(QMouseEvent * event)
if (did_draw) {
if (pref["LinkGraphMovement"].toBool()) {
double min=MinX();
double max=MaxX();
for (list<gGraphWindow *>::iterator g=link_zoom.begin();g!=link_zoom.end();g++) {
(*g)->SetXBounds(min,max);
(*g)->SetXBounds(min_x,max_x);
}
}
}
@ -601,11 +606,8 @@ void gGraphWindow::OnMouseRightRelease(QMouseEvent * event)
ZoomX(zoom_fact,x); //event.GetX()); // adds origin to zoom out.. Doesn't look that cool.
if (pref["LinkGraphMovement"].toBool()) {
double min=MinX();
double max=MaxX();
for (list<gGraphWindow *>::iterator g=link_zoom.begin();g!=link_zoom.end();g++) {
(*g)->SetXBounds(min,max);
(*g)->SetXBounds(min_x,max_x);
}
}
//}
@ -645,10 +647,10 @@ void gGraphWindow::OnMouseLeftDown(QMouseEvent * event)
m_mouseLClick.setY(y);
if (foobar && ((y>(m_scrY-GetBottomMargin())) && (y<(m_scrY)))) { //-GetBottomMargin())+20))) {
double rx=RealMaxX()-RealMinX();
double rx=rmax_x-rmin_x;
double qx=double(width)/rx;
double minx=MinX()-RealMinX();
double maxx=MaxX()-RealMinX();;
double minx=min_x-rmin_x;
double maxx=max_x-rmin_x;
int x1=(qx*minx);
int x2=(qx*maxx); // length in pixels
@ -733,10 +735,8 @@ void gGraphWindow::OnMouseLeftRelease(QMouseEvent * event)
did_draw=true;
}
}
if (!did_draw && hot1.contains(x,y) && !m_drag_foobar && m_mouseLDown) {
if (m_block_zoom) {
x-=GetLeftMargin();
@ -744,7 +744,7 @@ void gGraphWindow::OnMouseLeftRelease(QMouseEvent * event)
double mx=max_x-min_x;
double qx=(rx/width)*double(x);
if (mx>=rx) {
mx=1.0/(24.0*15.0);
mx=300000;//1.0/(24.0*15.0);
}
qx+=rmin_x;
qx-=mx/2.0;
@ -777,10 +777,8 @@ void gGraphWindow::OnMouseLeftRelease(QMouseEvent * event)
updateGL();
} else {
if (pref["LinkGraphMovement"].toBool()) {
double min=MinX();
double max=MaxX();
for (list<gGraphWindow *>::iterator g=link_zoom.begin();g!=link_zoom.end();g++) {
(*g)->SetXBounds(min,max);
(*g)->SetXBounds(min_x,max_x);
}
}
}
@ -788,7 +786,7 @@ void gGraphWindow::OnMouseLeftRelease(QMouseEvent * event)
LastGraphLDown=NULL;
}
void gGraphWindow::SetMargins(float top, float right, float bottom, float left)
void gGraphWindow::SetMargins(int top, int right, int bottom, int left)
{
m_marginTop=top;
m_marginBottom=bottom;
@ -825,7 +823,7 @@ void gGraphWindow::resizeGL(int w, int h)
}
void gGraphWindow::Render(float w, float h)
void gGraphWindow::Render(int w, int h)
{
if (m_gradient_background) {
glBegin(GL_QUADS);
@ -884,241 +882,90 @@ void gGraphWindow::paintGL()
swapBuffers(); // Dump to screen.
}
double gGraphWindow::MinX()
qint64 gGraphWindow::MinX()
{
//static bool f=true; //need a bool for each one, and reset when a layer reports data change.
//if (!f) return min_x;
//f=false;
bool first=true;
double val=0,tmp;
qint64 val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if ((*l)->isEmpty()) continue;
tmp=(*l)->Minx();
if (!tmp) continue;
if (first) {
val=(*l)->MinX();
if (!((val==(*l)->MaxX()) && (val==0)))
val=tmp;
first=false;
} else {
tmp=(*l)->MinX();
if (!((tmp==(*l)->MaxX()) && (tmp==0))) {
if (tmp < val) val = tmp;
}
}
}
return min_x=val;
if (val) rmin_x=val;
return val;
}
double gGraphWindow::MaxX()
qint64 gGraphWindow::MaxX()
{
//static bool f=true;
//if (!f) return max_x;
//f=false;
bool first=true;
double val=0,tmp;
qint64 val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if ((*l)->isEmpty()) continue;
tmp=(*l)->Maxx();
if (!tmp) continue;
if (first) {
val=(*l)->MaxX();
if (!((val==(*l)->MinX()) && (val==0)))
val=tmp;
first=false;
} else {
tmp=(*l)->MaxX();
if (!((tmp==(*l)->MinX()) && (tmp==0))) {
if (tmp > val) val = tmp;
}
}
}
return max_x=val;
if (val) rmax_x=val;
return val;
}
double gGraphWindow::MinY()
EventDataType gGraphWindow::MinY()
{
//static bool f=true;
//if (!f) return min_y;
//f=false;
bool first=true;
double val=0,tmp;
EventDataType val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if ((*l)->isEmpty()) continue;
tmp=(*l)->Miny();
if (tmp==(*l)->Maxy()) continue;
if (first) {
val=(*l)->MinY();
if (!((val==(*l)->MaxY()) && (val==0)))
val=tmp;
first=false;
} else {
tmp=(*l)->MinY();
if (!((tmp==(*l)->MaxY()) && (tmp==0))) { // Ignore this layer if both are 0
if (tmp < val) val = tmp;
}
}
}
return min_y=val;
}
double gGraphWindow::MaxY()
{
//static bool f=true;
//if (!f) return max_y;
//f=false;
bool first=true;
double val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if (first) {
val=(*l)->MaxY();
if (!((val==(*l)->MinY()) && (val==0)))
first=false;
} else {
tmp=(*l)->MaxY();
if (!((tmp==(*l)->MinY()) && (tmp==0))) { // Ignore this layer if both are 0
if (tmp > val) val = tmp;
}
}
}
return max_y=val;
}
double gGraphWindow::RealMinX()
{
//static bool f=true;
//if (!f) return rmin_x;
//f=false;
bool first=true;
double val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if (first) {
val=(*l)->RealMinX();
if (!((val==(*l)->RealMaxX()) && (val==0)))
first=false;
} else {
tmp=(*l)->RealMinX();
if (!((tmp==(*l)->RealMaxX()) && (tmp==0))) { // Ignore this layer if both are 0
if (tmp < val) val = tmp;
}
}
}
return rmin_x=val;
}
double gGraphWindow::RealMaxX()
{
//static bool f=true;
//if (!f) return rmax_x;
//f=false;
bool first=true;
double val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if (first) {
val=(*l)->RealMaxX();
if (!((val==(*l)->RealMinX()) && (val==0)))
first=false;
} else {
tmp=(*l)->RealMaxX();
if (!((tmp==(*l)->RealMinX()) && (tmp==0))) { // Ignore this layer if both are 0
if (tmp > val) val = tmp;
}
}
}
return rmax_x=val;
}
double gGraphWindow::RealMinY()
{
//static bool f=true;
//if (!f) return rmin_y;
//f=false;
bool first=true;
double val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if (first) {
val=(*l)->RealMinY();
if (!((val==(*l)->RealMaxY()) && (val==0)))
first=false;
} else {
tmp=(*l)->RealMinY();
if (!((tmp==(*l)->RealMaxY()) && (tmp==0))) { // Ignore this if both are 0
if (tmp < val) val = tmp;
}
}
}
return rmin_y=val;
}
double gGraphWindow::RealMaxY()
EventDataType gGraphWindow::MaxY()
{
//static bool f=true;
//if (!f) return rmax_y;
//f=false;
bool first=true;
double val=0,tmp;
EventDataType val=0,tmp;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
if ((*l)->isEmpty()) continue;
tmp=(*l)->Maxy();
if (tmp==(*l)->Miny()) continue;
if (first) {
val=(*l)->RealMaxY();
if (!((val==(*l)->RealMinY()) && (val==0))) // Does this create a loop??
val=tmp;
first=false;
} else {
tmp=(*l)->RealMaxY();
if (!((tmp==(*l)->RealMinY()) && (tmp==0))) { // Ignore this if both are 0
if (tmp > val) val = tmp;
}
}
}
return rmax_y=val;
}
void gGraphWindow::SetMinX(double v)
void gGraphWindow::SetMinX(qint64 v)
{
min_x=v;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
(*l)->SetMinX(v);
}
}
void gGraphWindow::SetMaxX(double v)
void gGraphWindow::SetMaxX(qint64 v)
{
max_x=v;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
(*l)->SetMaxX(v);
}
}
void gGraphWindow::SetMinY(double v)
void gGraphWindow::SetMinY(EventDataType v)
{
min_y=v;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
(*l)->SetMinY(v);
}
}
void gGraphWindow::SetMaxY(double v)
void gGraphWindow::SetMaxY(EventDataType v)
{
max_y=v;
for (list<gLayer *>::iterator l=layers.begin();l!=layers.end();l++) {
(*l)->SetMaxY(v);
}
}
void gGraphWindow::DataChanged(gLayer *layer)
{
QDateTime n=QDateTime::currentDateTime();
double t=ti.msecsTo(n);
ti=n;
if (layer) {
MinX(); MinY(); MaxX(); MaxY();
RealMinX(); RealMinY(); RealMaxX(); RealMaxY();
} else {
max_x=min_x=0;
}
//long l=t.GetMilliseconds().GetLo();
//wxLogMessage(wxString::Format(wxT("%li"),l));
if ((t<2) && (layer!=lastlayer)) {
lastlayer=layer;
return;
}
lastlayer=layer;
// This is possibly evil.. It needs to push one refresh event for all layers
// Assmption currently is Refresh que does skip
// updateGL();
}

View File

@ -56,83 +56,83 @@ public:
// For mouse to screen use only.. work in OpenGL points where possible
const QString & Title(void ) { return m_title; }
void SetMargins(float top, float right, float bottom, float left); // OpenGL width of each corners margin
void SetMargins(int top, int right, int bottom, int left); // OpenGL width of each corners margin
float GetTopMargin(void) const { return m_marginTop; }
float GetBottomMargin(void) const { return m_marginBottom; }
float GetLeftMargin(void) const { return m_marginLeft; }
float GetRightMargin(void) const { return m_marginRight; }
int GetTopMargin(void) const { return m_marginTop; }
int GetBottomMargin(void) const { return m_marginBottom; }
int GetLeftMargin(void) const { return m_marginLeft; }
int GetRightMargin(void) const { return m_marginRight; }
void SetTopMargin(float i) { m_marginTop=i; }
void SetBottomMargin(float i) { m_marginBottom=i; }
void SetLeftMargin(float i) { m_marginLeft=i; }
void SetRightMargin(float i) { m_marginRight=i; }
void SetTopMargin(int i) { m_marginTop=i; }
void SetBottomMargin(int i) { m_marginBottom=i; }
void SetLeftMargin(int i) { m_marginLeft=i; }
void SetRightMargin(int i) { m_marginRight=i; }
inline float Width() { return m_scrX-m_marginLeft-m_marginRight; } // Width of OpenGL main drawing area
inline int Width() { return m_scrX-m_marginLeft-m_marginRight; } // Width of OpenGL main drawing area
inline int Height() { return m_scrY-m_marginTop-m_marginBottom; } // Height of ""...
void LinkZoom(gGraphWindow *g) { link_zoom.push_back(g); } // Linking graphs changes zoom behaviour..
//void LinkMove(gGraphWindow *g) { link_move.push_back(g); } // Linking graphs changes zoom behaviour..
virtual double MinX();
virtual double MaxX();
virtual double MinY();
virtual double MaxY();
virtual qint64 MinX();
virtual qint64 MaxX();
virtual EventDataType MinY();
virtual EventDataType MaxY();
virtual double RealMinX();
/* virtual double RealMinX();
virtual double RealMaxX();
virtual double RealMinY();
virtual double RealMaxY();
virtual double RealMaxY();*/
virtual void SetMinX(double v);
virtual void SetMaxX(double v);
virtual void SetMinY(double v);
virtual void SetMaxY(double v);
virtual void SetMinX(qint64 v);
virtual void SetMaxX(qint64 v);
virtual void SetMinY(EventDataType v);
virtual void SetMaxY(EventDataType v);
virtual void ResetXBounds();
virtual void SetXBounds(double minx, double maxx);
virtual void ResetBounds();
virtual void SetXBounds(qint64 minx, qint64 maxx);
virtual void ZoomX(double mult,int origin_px);
virtual void ZoomXPixels(int x1, int x2); // Zoom between two selected points on screen
virtual void ZoomXPixels(int x1,int x2,double &rx1,double &rx2);
virtual void ZoomXPixels(int x1,int x2,qint64 &rx1,qint64 &rx2);
virtual void MoveX(int i); // Move x bounds by i Pixels
virtual void MoveX(int i,double &min, double & max);
virtual void MoveX(int i,qint64 &min, qint64 & max);
inline float x2p(double x) {
inline int x2p(qint64 x) {
double xx=max_x-min_x;
double wid=Width();
double w=((wid/xx)*(x-min_x));
double w=((wid/xx)*double(x-min_x));
return w+GetLeftMargin();
}
inline double p2x(float px) {
inline qint64 p2x(int px) {
double xx=max_x-min_x;
double wx=px-GetLeftMargin();
double ww=wx/Width();
return min_x+(xx*ww);
}
inline int y2p(double y) {
inline int y2p(EventDataType y) {
double yy=max_y-min_y;
double h=(Height()/yy)*(y-min_y);
double h=(Height()/yy)*double(y-min_y);
return h+GetBottomMargin();
}
inline double p2y(float py) {
inline EventDataType p2y(int py) {
double yy=max_y-min_y;
double hy=py-GetBottomMargin();
double hh=hy/Height();
return min_y+(yy*hh);
}
void Render(float scrx,float scry);
void Render(int scrx,int scry);
//virtual void Update();
//virtual void Update();
void AddLayer(gLayer *l);
virtual void DataChanged(gLayer *layer);
//virtual void DataChanged(gLayer *layer);
double max_x,min_x,max_y,min_y;
double rmax_x,rmin_x,rmax_y,rmin_y;
qint64 max_x,min_x,max_y,min_y;
qint64 rmax_x,rmin_x,rmax_y,rmin_y;
void SetBlockZoom(bool b) { m_block_zoom=b; }
//void SetBlockMove(bool b) { m_block_move=b; }
@ -141,7 +141,7 @@ public:
//FTFont *texfont;
void SetGradientBackground(bool b) { m_gradient_background=b; }
bool GradientBackground() { return m_gradient_background; }
bool isEmpty();
void SetSplitter(QSplitter *s) { splitter=s; }
bool isDraggingGraph() { return m_dragGraph; }
protected:
@ -165,7 +165,7 @@ public:
int m_scrY;
QPoint m_mouseLClick,m_mouseRClick,m_mouseRClick_start;
float m_marginTop, m_marginRight, m_marginBottom, m_marginLeft;
int m_marginTop, m_marginRight, m_marginBottom, m_marginLeft;
QRect m_mouseRBrect,m_mouseRBlast;
bool m_mouseLDown,m_mouseRDown,m_datarefresh;

View File

@ -9,9 +9,7 @@
Day::Day(Machine *m)
:machine(m)
{
d_firstsession=true;
sessions.clear();
}
Day::~Day()
{
@ -124,53 +122,7 @@ EventDataType Day::summary_weighted_avg(MachineCode code)
}
EventDataType Day::min(MachineCode code,int field)
{
EventDataType val=0,tmp;
bool fir=true;
// Cache this?
vector<Session *>::iterator s;
for (s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
tmp=sess.min_event_field(code,field);
if (fir) {
val=tmp;
fir=false;
} else {
if (val>tmp) val=tmp;
}
}
}
return val;
}
EventDataType Day::max(MachineCode code,int field)
{
EventDataType val=0,tmp;
bool fir=true;
// Cache this?
// Don't assume sessions are in order.
vector<Session *>::iterator s;
for (s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
tmp=sess.max_event_field(code,field);
if (fir) {
val=tmp;
fir=false;
} else {
if (val<tmp) val=tmp;
}
}
}
return val;
}
EventDataType Day::avg(MachineCode code,int field)
EventDataType Day::avg(MachineCode code)
{
double val=0;
// Cache this?
@ -180,8 +132,8 @@ EventDataType Day::avg(MachineCode code,int field)
// Don't assume sessions are in order.
for (s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
val+=sess.avg_event_field(code,field);
if (sess.eventlist.find(code)!=sess.eventlist.end()) {
val+=sess.avg(code);
cnt++;
}
}
@ -189,7 +141,7 @@ EventDataType Day::avg(MachineCode code,int field)
return EventDataType(val/float(cnt));
}
EventDataType Day::sum(MachineCode code,int field)
EventDataType Day::sum(MachineCode code)
{
// Cache this?
EventDataType val=0;
@ -197,33 +149,21 @@ EventDataType Day::sum(MachineCode code,int field)
for (s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
val+=sess.sum_event_field(code,field);
if (sess.eventlist.find(code)!=sess.eventlist.end()) {
val+=sess.sum(code);
}
}
return val;
}
int Day::count(MachineCode code)
{
int val=0;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
val+=sess.count_events(code);
}
}
return val;
}
EventDataType Day::weighted_avg(MachineCode code,int field)
EventDataType Day::weighted_avg(MachineCode code)
{
double s0=0,s1=0,s2=0;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
if (sess.eventlist.find(code)!=sess.eventlist.end()) {
s0=sess.hours();
s1+=sess.weighted_avg_event_field(code,field)*s0;
s1+=sess.weighted_avg(code)*s0;
s2+=s0;
}
}
@ -233,22 +173,22 @@ EventDataType Day::weighted_avg(MachineCode code,int field)
// Total session time in milliseconds
qint64 Day::total_time()
{
d_totaltime=0;
qint64 d_totaltime=0;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
d_totaltime+=sess.last()-sess.first();
}
return d_totaltime;
}
EventDataType Day::percentile(MachineCode code,int field,double percent)
EventDataType Day::percentile(MachineCode code,double percent)
{
double val=0;
int cnt=0;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
val+=sess.percentile(code,field,percent);
if (sess.eventlist.find(code)!=sess.eventlist.end()) {
val+=sess.percentile(code,percent);
cnt++;
}
}
@ -263,16 +203,14 @@ qint64 Day::first(MachineCode code)
qint64 tmp;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
tmp=sess.events[code][0]->time();
tmp=(*s)->first(code);
if (!tmp) continue;
if (!date) {
date=tmp;
} else {
if (tmp<date) date=tmp;
}
}
}
return date;
}
@ -282,25 +220,59 @@ qint64 Day::last(MachineCode code)
qint64 tmp;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
Session & sess=*(*s);
if (sess.events.find(code)!=sess.events.end()) {
vector<Event *>::reverse_iterator i=sess.events[code].rbegin();
if (i==sess.events[code].rend()) {
qWarning() << "Day::last() i==sess.events[code].rend()";
continue;
}
//assert(i!=sess.events[code].rend());
tmp=(*i)->time();
tmp=(*s)->last(code);
if (!tmp) continue;
if (!date) {
date=tmp;
} else {
if (tmp>date) date=tmp;
}
}
}
return date;
}
EventDataType Day::min(MachineCode code)
{
EventDataType min=0;
EventDataType tmp;
bool first=true;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
if ((*s)->eventlist.find(code)==(*s)->eventlist.end()) continue;
tmp=(*s)->min(code);
if (first) {
min=tmp;
first=false;
} else {
if (tmp<min) min=tmp;
}
}
return min;
}
EventDataType Day::max(MachineCode code)
{
EventDataType max=0;
EventDataType tmp;
bool first=true;
for (vector<Session *>::iterator s=sessions.begin();s!=sessions.end();s++) {
if ((*s)->eventlist.find(code)==(*s)->eventlist.end()) continue;
tmp=(*s)->max(code);
if (first) {
max=tmp;
first=false;
} else {
if (tmp>max) max=tmp;
}
}
return max;
}
int Day::count(MachineCode code)
{
int sum=0;
for (unsigned i=0;i<sessions.size();i++) {
sum+=sessions[i]->count(code);
}
return sum;
}
void Day::OpenEvents()
{
vector<Session *>::iterator s;
@ -310,11 +282,3 @@ void Day::OpenEvents()
}
}
void Day::OpenWaveforms()
{
vector<Session *>::iterator s;
for (s=sessions.begin();s!=sessions.end();s++) {
(*s)->OpenWaveforms();
}
}

View File

@ -7,7 +7,9 @@
#ifndef DAY_H
#define DAY_H
#include "SleepLib/machine_common.h"
#include "SleepLib/machine.h"
#include "SleepLib/event.h"
#include "SleepLib/session.h"
class OneTypePerDay
@ -25,13 +27,10 @@ public:
MachineType machine_type();
EventDataType min(MachineCode code,int field=0);
EventDataType max(MachineCode code,int field=0);
EventDataType avg(MachineCode code,int field=0);
EventDataType sum(MachineCode code,int field=0);
int count(MachineCode code);
EventDataType weighted_avg(MachineCode code,int field=0);
EventDataType percentile(MachineCode mc,int field,double percent);
EventDataType avg(MachineCode code);
EventDataType sum(MachineCode code);
EventDataType weighted_avg(MachineCode code);
EventDataType percentile(MachineCode mc,double percent);
// Note, the following convert to doubles without considering the consequences fully.
EventDataType summary_avg(MachineCode code);
@ -40,29 +39,31 @@ public:
EventDataType summary_min(MachineCode code);
EventDataType summary_max(MachineCode code);
qint64 first() { return d_first; }
qint64 last() { return d_last; }
qint64 first(MachineCode code);
qint64 last(MachineCode code);
qint64 first() { return d_first; };
qint64 last() { return d_last; };
EventDataType min(MachineCode code);
EventDataType max(MachineCode code);
int count(MachineCode code);
qint64 total_time(); // in milliseconds
double hours() { return double(total_time())/3600000.0; };
double hours() { return double(total_time())/3600000.0; }
Session *operator [](int i) { return sessions[i]; };
Session *operator [](int i) { return sessions[i]; }
vector<Session *>::iterator begin() { return sessions.begin(); };
vector<Session *>::iterator end() { return sessions.end(); };
vector<Session *>::iterator begin() { return sessions.begin(); }
vector<Session *>::iterator end() { return sessions.end(); }
size_t size() { return sessions.size(); };
size_t size() { return sessions.size(); }
Machine *machine;
void OpenEvents();
void OpenWaveforms();
protected:
vector<Session *> sessions;
qint64 d_first,d_last;
qint64 d_totaltime;
private:
bool d_firstsession;
};

View File

@ -4,18 +4,192 @@
License: GPL
*********************************************************************/
#include <QDebug>
#include "event.h"
Event::Event(qint64 time,MachineCode code, EventDataType * data, int fields)
:e_time(time),e_code(code)
EventList::EventList(MachineCode code,EventListType et,EventDataType gain, EventDataType offset, EventDataType min, EventDataType max,double rate)
:m_code(code),m_type(et),m_gain(gain),m_offset(offset),m_min(min),m_max(max),m_rate(rate)
{
e_fields=fields;
for (int i=0; i<fields; i++) {
e_data.push_back(data[i]);
m_first=m_last=0;
m_count=0;
if (min==max) { // Update Min & Max unless forceably set here..
m_update_minmax=true;
m_min=999999999;
m_max=-999999999;
} else {
m_update_minmax=false;
}
// Reserve a few to increase performace??
}
EventList::~EventList()
{
}
qint64 EventList::time(int i)
{
if (m_type==EVL_Waveform) {
qint64 t=m_first+(double(i)*m_rate);
return t;
}
return m_time[i];
}
EventDataType EventList::data(int i)
{
return EventDataType(m_data[i])*m_gain;
}
void EventList::AddEvent(qint64 time, EventStoreType data)
{
// Apply gain & offset
m_data.push_back(data);
EventDataType val=data;
val*=m_gain;
val+=m_offset;
m_count++;
if (m_update_minmax) {
if (m_min>val) m_min=val;
if (m_max<val) m_max=val;
}
m_time.push_back(time);
if (!m_first) {
m_first=time;
m_last=time;
}
if (m_first>time) m_first=time;
if (m_last<time) m_last=time;
}
// Adds a consecutive waveform chunk
void EventList::AddWaveform(qint64 start, qint16 * data, int recs, qint64 duration)
{
if (m_type!=EVL_Waveform) {
qWarning() << "Attempted to add waveform data to non-waveform object";
return;
}
if (!m_rate) {
qWarning() << "Attempted to add waveform without setting sample rate";
return;
}
// duration=recs*rate;
qint64 last=start+duration;
if (!m_first) {
m_first=start;
m_last=last;
}
if (m_last>start) {
//qWarning() << "Attempted to add waveform with previous timestamp";
// return;
// technically start should equal m_last+1 sample.. check this too.
}
if (m_last<last) {
m_last=last;
}
// TODO: Check waveform chunk really is contiguos
//double rate=duration/recs;
//realloc buffers.
m_count+=recs;
m_data.reserve(m_count);
EventDataType val;
for (int i=0;i<recs;i++) {
val=EventDataType(data[i])*m_gain+m_offset;
if (m_update_minmax) {
if (m_min>val) m_min=val;
if (m_max<val) m_max=val;
}
m_data.push_back(data[i]);
}
}
Event::~Event()
void EventList::AddWaveform(qint64 start, unsigned char * data, int recs, qint64 duration)
{
if (m_type!=EVL_Waveform) {
qWarning() << "Attempted to add waveform data to non-waveform object";
return;
}
if (!m_rate) {
qWarning() << "Attempted to add waveform without setting sample rate";
return;
}
// duration=recs*rate;
qint64 last=start+duration;
if (!m_first) {
m_first=start;
m_last=last;
}
if (m_last>start) {
//qWarning() << "Attempted to add waveform with previous timestamp";
// return;
};
// technically start should equal m_last+1 sample.. check this too.
}
if (m_last<last) {
m_last=last;
}
// TODO: Check waveform chunk really is contiguos
//realloc buffers.
m_count+=recs;
m_data.reserve(m_count);
EventDataType val;
for (int i=0;i<recs;i++) {
val=EventDataType(data[i])*m_gain+m_offset;
if (m_update_minmax) {
if (m_min>val) m_min=val;
if (m_max<val) m_max=val;
}
m_data.push_back(data[i]);
}
}
void EventList::AddWaveform(qint64 start, char * data, int recs, qint64 duration)
{
if (m_type!=EVL_Waveform) {
qWarning() << "Attempted to add waveform data to non-waveform object";
return;
}
if (!m_rate) {
qWarning() << "Attempted to add waveform without setting sample rate";
return;
}
// duration=recs*rate;
qint64 last=start+duration;
if (!m_first) {
m_first=start;
m_last=last;
} else {
if (m_last>start) {
//qWarning() << "Attempted to add waveform with previous timestamp";
//return;
// technically start should equal m_last+1 sample.. check this too.
}
if (m_last<last) {
m_last=last;
}
}
// TODO: Check waveform chunk really is contiguos
//realloc buffers.
m_count+=recs;
m_data.reserve(m_count);
EventDataType val;
for (int i=0;i<recs;i++) {
val=EventDataType(data[i])*m_gain+m_offset;
if (m_update_minmax) {
if (m_min>val) m_min=val;
if (m_max<val) m_max=val;
}
m_data.push_back(data[i]);
}
}

View File

@ -8,34 +8,64 @@
#define EVENT_H
#include <QDateTime>
#include "SleepLib/session.h"
#include "machine_common.h"
typedef float EventDataType;
class Event
enum EventListType { EVL_Waveform, EVL_Event };
class EventList
{
friend class Session;
public:
Event(qint64 time,MachineCode code,EventDataType * data,int fields);
~Event();
EventDataType operator[](short i) {
if (i<e_fields) return e_data[i];
else return 0;
};
const qint64 & time() {
return e_time;
};
MachineCode code() {
return e_code;
};
short fields() {
return e_fields;
};
EventList(MachineCode code,EventListType et,EventDataType gain=1.0, EventDataType offset=0.0, EventDataType min=0.0, EventDataType max=0.0, double rate=0.0);
~EventList();
void AddEvent(qint64 time, EventStoreType data);
void AddWaveform(qint64 start, qint16 * data, int recs, qint64 duration);
void AddWaveform(qint64 start, unsigned char * data, int recs, qint64 duration);
void AddWaveform(qint64 start, char * data, int recs, qint64 duration);
inline const int & count() { return m_count; }
inline EventStoreType raw(int i) { return m_data[i]; }
EventDataType data(int i);
qint64 time(int i);
inline const qint64 & first() { return m_first; }
inline const qint64 & last() { return m_last; }
inline qint64 duration() { return m_last-m_first; }
void setGain(EventDataType v) { m_gain=v; }
void setOffset(EventDataType v) { m_offset=v; }
void setMin(EventDataType v) { m_min=v; }
void setMax(EventDataType v) { m_max=v; }
void setRate(EventDataType v) { m_rate=v; }
inline const EventDataType & min() { return m_min; }
inline const EventDataType & max() { return m_max; }
inline const EventDataType & gain() { return m_gain; }
inline const EventDataType & offset() { return m_offset; }
inline const EventDataType & rate() { return m_rate; }
inline const EventListType & type() { return m_type; }
inline const MachineCode & code() { return m_code; }
inline const bool & update_minmax() { return m_update_minmax; }
const vector<EventStoreType> & getData() { return m_data; }
const vector<qint64> & getTime() { return m_time; }
protected:
qint64 e_time;
MachineCode e_code;
short e_fields;
vector<EventDataType> e_data;
vector<qint64> m_time;
vector<EventStoreType> m_data;
MachineCode m_code;
EventListType m_type;
int m_count;
EventDataType m_gain;
EventDataType m_offset;
EventDataType m_min;
EventDataType m_max;
EventDataType m_rate; // Waveform sample rate
qint64 m_first,m_last;
bool m_update_minmax;
};
#endif // EVENT_H

View File

@ -196,9 +196,15 @@ bool CMS50Loader::OpenSPORFile(QString path,Machine *mach,Profile *profile)
EventDataType cp,cs;
Session *sess=new Session(mach,sessid);
sess->set_first(starttime);
sess->AddEvent(new Event(starttime,OXI_Pulse,&last_pulse,1));
sess->AddEvent(new Event(starttime,OXI_SPO2,&last_spo2,1));
sess->UpdateFirst(starttime);
EventList *oxip=new EventList(OXI_Pulse,EVL_Event);
EventList *oxis=new EventList(OXI_SPO2,EVL_Event);
sess->eventlist[OXI_Pulse].push_back(oxip);
sess->eventlist[OXI_SPO2].push_back(oxis);
oxip->AddEvent(starttime,last_pulse);
oxis->AddEvent(starttime,last_spo2);
//sess->AddEvent(new Event(starttime,OXI_Pulse,0,&last_pulse,1));
//sess->AddEvent(new Event(starttime,OXI_SPO2,0,&last_spo2,1));
EventDataType PMin=0,PMax=0,SMin=0,SMax=0,PAvg=0,SAvg=0;
int PCnt=0,SCnt=0;
@ -213,7 +219,8 @@ bool CMS50Loader::OpenSPORFile(QString path,Machine *mach,Profile *profile)
cp=buffer[i];
cs=buffer[i+1];
if (last_pulse!=cp) {
sess->AddEvent(new Event(tt,OXI_Pulse,&cp,1));
oxip->AddEvent(tt,cp);
//sess->AddEvent(new Event(tt,OXI_Pulse,0,&cp,1));
if (tt>lasttime) lasttime=tt;
if (cp>0) {
if (first_p) {
@ -227,7 +234,8 @@ bool CMS50Loader::OpenSPORFile(QString path,Machine *mach,Profile *profile)
}
}
if (last_spo2!=cs) {
sess->AddEvent(new Event(tt,OXI_SPO2,&cs,1));
oxis->AddEvent(tt,cs);
//sess->AddEvent(new Event(tt,OXI_SPO2,0,&cs,1));
if (tt>lasttime) lasttime=tt;
if (cs>0) {
if (first_s) {
@ -246,10 +254,10 @@ bool CMS50Loader::OpenSPORFile(QString path,Machine *mach,Profile *profile)
if (SMax<cs) SMax=cs;
tt+=1000; // An educated guess of 1 second. Verified by gcz@cpaptalk
}
if (cp) sess->AddEvent(new Event(tt,OXI_Pulse,&cp,1));
if (cs) sess->AddEvent(new Event(tt,OXI_SPO2,&cs,1));
if (cp) oxip->AddEvent(tt,cp);//sess->AddEvent(new Event(tt,OXI_Pulse,0,&cp,1));
if (cs) oxis->AddEvent(tt,cs);//sess->AddEvent(new Event(tt,OXI_SPO2,0,&cs,1));
sess->set_last(lasttime);
sess->UpdateLast(tt);
//double t=sess->last()-sess->first().toTime_t();
//double hours=(t/3600.0);
//sess->set_hours(hours);

File diff suppressed because it is too large Load Diff

View File

@ -13,7 +13,7 @@ License: GPL
#include <QMessageBox>
#include <QProgressBar>
#include <QDebug>
#include <math.h>
#include <cmath>
#include "resmed_loader.h"
#include "SleepLib/session.h"
@ -100,6 +100,7 @@ bool EDFParser::Parse()
num_data_records=QString::fromAscii(header.num_data_records,8).toLong(&ok);
if (!ok)
return false;
dur_data_record=QString::fromAscii(header.dur_data_records,8).toDouble(&ok)*1000.0;
if (!ok)
return false;
@ -121,11 +122,18 @@ bool EDFParser::Parse()
}
for (int i=0;i<num_signals;i++) edfsignals[i]->transducer_type=Read(80);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_dimension=Read(8);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_minimum=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_maximum=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->digital_minimum=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->digital_maximum=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_minimum=Read(8).toDouble(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->physical_maximum=Read(8).toDouble(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->digital_minimum=Read(8).toDouble(&ok);
for (int i=0;i<num_signals;i++) {
EDFSignal & e=*edfsignals[i];
e.digital_maximum=Read(8).toDouble(&ok);
e.gain=(e.physical_maximum-e.physical_minimum)/(e.digital_maximum-e.digital_minimum);
e.offset=0;
}
for (int i=0;i<num_signals;i++) edfsignals[i]->prefiltering=Read(80);
for (int i=0;i<num_signals;i++) edfsignals[i]->nr=Read(8).toLong(&ok);
for (int i=0;i<num_signals;i++) edfsignals[i]->reserved=Read(32);
@ -349,26 +357,26 @@ int ResmedLoader::Open(QString & path,Profile *profile)
m->AddSession(sess,profile); // Adding earlier than I really like here..
}
if (!done && sess) {
sess->summary[CPAP_PressureMedian]=sess->avg_event_field(CPAP_Pressure,0);
sess->summary[CPAP_PressureAverage]=sess->weighted_avg_event_field(CPAP_Pressure,0);
sess->summary[CPAP_PressureMinAchieved]=sess->min_event_field(CPAP_Pressure,0);
sess->summary[CPAP_PressureMaxAchieved]=sess->max_event_field(CPAP_Pressure,0);
sess->summary[CPAP_PressureMedian]=sess->avg(CPAP_Pressure);
sess->summary[CPAP_PressureAverage]=sess->weighted_avg(CPAP_Pressure);
sess->summary[CPAP_PressureMinAchieved]=sess->min(CPAP_Pressure);
sess->summary[CPAP_PressureMaxAchieved]=sess->max(CPAP_Pressure);
sess->summary[CPAP_PressureMin]=sess->summary[CPAP_PressureMinAchieved];
sess->summary[CPAP_PressureMax]=sess->summary[CPAP_PressureMaxAchieved];
sess->summary[CPAP_LeakMinimum]=sess->min_event_field(CPAP_Leak,0);
sess->summary[CPAP_LeakMaximum]=sess->max_event_field(CPAP_Leak,0); // should be merged..
sess->summary[CPAP_LeakMedian]=sess->avg_event_field(CPAP_Leak,0);
sess->summary[CPAP_LeakAverage]=sess->weighted_avg_event_field(CPAP_Leak,0);
sess->summary[CPAP_LeakMinimum]=sess->min(CPAP_Leak);
sess->summary[CPAP_LeakMaximum]=sess->max(CPAP_Leak); // should be merged..
sess->summary[CPAP_LeakMedian]=sess->avg(CPAP_Leak);
sess->summary[CPAP_LeakAverage]=sess->weighted_avg(CPAP_Leak);
sess->summary[CPAP_Snore]=sess->sum_event_field(CPAP_Snore,0);
sess->summary[CPAP_SnoreMinimum]=sess->min_event_field(CPAP_Snore,0);
sess->summary[CPAP_SnoreMaximum]=sess->max_event_field(CPAP_Snore,0);
sess->summary[CPAP_SnoreMedian]=sess->avg_event_field(CPAP_Snore,0);
sess->summary[CPAP_SnoreAverage]=sess->weighted_avg_event_field(CPAP_Snore,0);
sess->summary[CPAP_Obstructive]=sess->count_events(CPAP_Obstructive);
sess->summary[CPAP_Hypopnea]=sess->count_events(CPAP_Hypopnea);
sess->summary[CPAP_ClearAirway]=sess->count_events(CPAP_ClearAirway);
sess->summary[CPAP_Snore]=sess->sum(CPAP_Snore);
sess->summary[CPAP_SnoreMinimum]=sess->min(CPAP_Snore);
sess->summary[CPAP_SnoreMaximum]=sess->max(CPAP_Snore);
sess->summary[CPAP_SnoreMedian]=sess->avg(CPAP_Snore);
sess->summary[CPAP_SnoreAverage]=sess->weighted_avg(CPAP_Snore);
sess->summary[CPAP_Obstructive]=sess->count(CPAP_Obstructive);
sess->summary[CPAP_Hypopnea]=sess->count(CPAP_Hypopnea);
sess->summary[CPAP_ClearAirway]=sess->count(CPAP_ClearAirway);
sess->summary[CPAP_Mode]=MODE_APAP;
}
@ -381,21 +389,23 @@ int ResmedLoader::Open(QString & path,Profile *profile)
bool ResmedLoader::LoadEVE(Session *sess,EDFParser &edf)
{
// EVEnt records have useless duration record.
QString t;
long recs;
double totaldur,duration;
double duration;
char * data;
char c;
long pos;
bool sign,ok;
double d;
double tt;
EventDataType fields[3];
MachineCode code;
//Event *e;
totaldur=edf.GetNumDataRecords()*edf.GetDuration();
//totaldur=edf.GetNumDataRecords()*edf.GetDuration();
//sess->set_first(edf.startdate);
EventList *EL[4]={NULL};
sess->UpdateFirst(edf.startdate);
//if (edf.enddate>edf.startdate) sess->set_last(edf.enddate);
for (int s=0;s<edf.GetNumSignals();s++) {
recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords()*2;
@ -404,6 +414,7 @@ bool ResmedLoader::LoadEVE(Session *sess,EDFParser &edf)
data=(char *)edf.edfsignals[s]->data;
pos=0;
tt=edf.startdate;
sess->UpdateFirst(tt);
duration=0;
while (pos<recs) {
c=data[pos];
@ -423,7 +434,7 @@ bool ResmedLoader::LoadEVE(Session *sess,EDFParser &edf)
break;
}
if (!sign) d=-d;
tt=edf.startdate+(d*1000.0);
tt=edf.startdate+qint64(d*1000.0);
duration=0;
// First entry
@ -455,14 +466,35 @@ bool ResmedLoader::LoadEVE(Session *sess,EDFParser &edf)
t+=tolower(data[pos++]);
} while ((data[pos]!=20) && (pos<recs)); // start code
if (!t.isEmpty()) {
code=MC_UNKNOWN;
if (t=="obstructive apnea") code=CPAP_Obstructive;
else if (t=="hypopnea") code=CPAP_Hypopnea;
else if (t=="apnea") code=CPAP_Apnea;
else if (t=="central apnea") code=CPAP_ClearAirway;
if (code!=MC_UNKNOWN) {
fields[0]=duration;
sess->AddEvent(new Event(tt,code,fields,1));
//code=MC_UNKNOWN;
if (t=="obstructive apnea") {
code=CPAP_Obstructive;
if (!EL[0]) {
EL[0]=new EventList(code,EVL_Event);
sess->eventlist[code].push_back(EL[0]);
}
EL[0]->AddEvent(tt,duration);
} else if (t=="hypopnea") {
code=CPAP_Hypopnea;
if (!EL[1]) {
EL[1]=new EventList(code,EVL_Event);
sess->eventlist[code].push_back(EL[1]);
}
EL[1]->AddEvent(tt,duration);
} else if (t=="apnea") {
code=CPAP_Apnea;
if (!EL[2]) {
EL[2]=new EventList(code,EVL_Event);
sess->eventlist[code].push_back(EL[2]);
}
EL[2]->AddEvent(tt,duration);
} else if (t=="central apnea") {
code=CPAP_ClearAirway;
if (!EL[3]) {
EL[3]=new EventList(code,EVL_Event);
sess->eventlist[code].push_back(EL[3]);
}
EL[3]->AddEvent(tt,duration);
} else {
if (t!="recording starts") {
qDebug() << "Unknown ResMed annotation field: " << t;
@ -478,6 +510,7 @@ bool ResmedLoader::LoadEVE(Session *sess,EDFParser &edf)
while ((data[pos]==0) && pos<recs) pos++;
if (pos>=recs) break;
}
sess->UpdateLast(tt);
// qDebug(data);
}
return true;
@ -485,49 +518,73 @@ bool ResmedLoader::LoadEVE(Session *sess,EDFParser &edf)
bool ResmedLoader::LoadBRP(Session *sess,EDFParser &edf)
{
QString t;
sess->set_first(edf.startdate);
sess->set_last(edf.enddate);
sess->UpdateFirst(edf.startdate);
qint64 duration=edf.GetNumDataRecords()*edf.GetDuration();
sess->UpdateLast(edf.startdate+duration);
for (int s=0;s<edf.GetNumSignals();s++) {
EDFSignal & es=*edf.edfsignals[s];
//qDebug() << "BRP:" << es.digital_maximum << es.digital_minimum << es.physical_maximum << es.physical_minimum;
long recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords();
MachineCode code;
if (edf.edfsignals[s]->label=="Flow") code=CPAP_FlowRate;
else if (edf.edfsignals[s]->label=="Mask Pres") {
if (edf.edfsignals[s]->label=="Flow") {
code=CPAP_FlowRate;
} else if (edf.edfsignals[s]->label=="Mask Pres") {
code=CPAP_MaskPressure;
//for (int i=0;i<recs;i++) edf.edfsignals[s]->data[i]/=50.0;
} else {
qDebug() << "Unknown Signal " << edf.edfsignals[s]->label;
continue;
}
Waveform *w=new Waveform(edf.startdate,code,edf.edfsignals[s]->data,recs,duration,edf.edfsignals[s]->digital_minimum,edf.edfsignals[s]->digital_maximum);
edf.edfsignals[s]->data=NULL; // so it doesn't get deleted when edf gets trashed.
sess->AddWaveform(w);
double rate=double(duration)/double(recs);
//es.gain=1;
EventList *a=new EventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
a->AddWaveform(edf.startdate,es.data,recs,duration);
if (code==CPAP_MaskPressure) {
/*int v=ceil(a->max()/1);
a->setMax(v*1);
v=floor(a->min()/1);
a->setMin(v*1); */
} else if (code==CPAP_FlowRate) {
a->setMax(1);
a->setMin(-1);
}
sess->eventlist[code].push_back(a);
//delete edf.edfsignals[s]->data;
//edf.edfsignals[s]->data=NULL; // so it doesn't get deleted when edf gets trashed.
}
return true;
}
void ResmedLoader::ToTimeDelta(Session *sess,EDFParser &edf, qint16 *data, MachineCode code, long recs, qint64 duration,EventDataType divisor)
EventList * ResmedLoader::ToTimeDelta(Session *sess,EDFParser &edf, EDFSignal & es, MachineCode code, long recs, qint64 duration,EventDataType min,EventDataType max)
{
bool first=true;
double rate=(duration/recs); // milliseconds per record
double tt=edf.startdate;
//sess->UpdateFirst(tt);
EventDataType c,last;
//if (gain==0) gain=1;
EventList *el=new EventList(code,EVL_Event,es.gain,es.offset,min,max);
sess->eventlist[code].push_back(el);
for (int i=0;i<recs;i++) {
c=data[i]/divisor;
c=es.data[i];
if (first) {
sess->AddEvent(new Event(tt,code,&c,1));
el->AddEvent(tt,c);
first=false;
} else {
if (last!=c) {
sess->AddEvent(new Event(tt,code,&c,1));
el->AddEvent(tt,c);
}
}
tt+=rate;
last=c;
}
sess->AddEvent(new Event(tt,code,&c,1)); // add one at the end..
el->AddEvent(tt,c);
sess->UpdateLast(tt);
return el;
}
bool ResmedLoader::LoadSAD(Session *sess,EDFParser &edf)
{
@ -542,66 +599,86 @@ bool ResmedLoader::LoadPLD(Session *sess,EDFParser &edf)
// Is it save to assume the order does not change here?
enum PLDType { MaskPres=0, TherapyPres, ExpPress, Leak, RR, Vt, Mv, SnoreIndex, FFLIndex, U1, U2 };
sess->set_first(edf.startdate);
sess->set_last(edf.enddate);
sess->UpdateFirst(edf.startdate);
qint64 duration=edf.GetNumDataRecords()*edf.GetDuration();
sess->UpdateLast(edf.startdate+duration);
QString t;
int emptycnt=0;
for (int s=0;s<edf.GetNumSignals();s++) {
long recs=edf.edfsignals[s]->nr*edf.GetNumDataRecords();
EDFSignal & es=*edf.edfsignals[s];
long recs=es.nr*edf.GetNumDataRecords();
double rate=double(duration)/double(recs);
//qDebug() << "EVE:" << es.digital_maximum << es.digital_minimum << es.physical_maximum << es.physical_minimum << es.gain;
MachineCode code;
// if (s==TherapyPres) {
// for (int i=0;i<recs;i++) qDebug("%04i %i",i,edf.edfsignals[s]->data[i]);
// } else
if (edf.edfsignals[s]->label=="Snore Index") {
if (es.label=="Snore Index") {
code=CPAP_Snore;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration);
} else if (edf.edfsignals[s]->label=="Therapy Pres") {
//EventList *a=new EventList(code,EVL_Waveform,es.gain,es.offset,es.physical_minimum,es.physical_maximum,rate);
//sess->eventlist[code].push_back(a);
//a->AddWaveform(edf.startdate,es.data,recs,duration);
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
a->setMax(1);
a->setMin(0);
} else if (es.label=="Therapy Pres") {
code=CPAP_TherapyPressure;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration,50.0); //50.0
} else if (edf.edfsignals[s]->label=="MV") {
//EventList *a=new EventList(code,EVL_Waveform,es.gain,es.offset,es.physical_minimum,es.physical_maximum,rate);
//sess->eventlist[code].push_back(a);
//a->AddWaveform(edf.startdate,es.data,recs,duration);
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
} else if (es.label=="MV") {
code=CPAP_MinuteVentilation;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration);
//Waveform *w=new Waveform(edf.startdate,code,edf.edfsignals[s]->data,recs,duration,edf.edfsignals[s]->digital_minimum,edf.edfsignals[s]->digital_maximum);
//edf.edfsignals[s]->data=NULL; // so it doesn't get deleted when edf gets trashed.
//sess->AddWaveform(w);
} else if (edf.edfsignals[s]->label=="RR") {
//EventList *a=new EventList(code,EVL_Waveform,es.gain,es.offset,es.physical_minimum,es.physical_maximum,rate);
//sess->eventlist[code].push_back(a);
//a->AddWaveform(edf.startdate,es.data,recs,duration);
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
} else if (es.label=="RR") {
code=CPAP_RespiratoryRate;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration);
//Waveform *w=new Waveform(edf.startdate,code,edf.edfsignals[s]->data,recs,duration,edf.edfsignals[s]->digital_minimum,edf.edfsignals[s]->digital_maximum);
//edf.edfsignals[s]->data=NULL; // so it doesn't get deleted when edf gets trashed.
//sess->AddWaveform(w);
} else if (edf.edfsignals[s]->label=="Vt") {
EventList *a=new EventList(code,EVL_Waveform,es.gain,es.offset,0,0,rate);
sess->eventlist[code].push_back(a);
a->AddWaveform(edf.startdate,es.data,recs,duration);
//ToTimeDelta(sess,edf,es, code,recs,duration);
} else if (es.label=="Vt") {
code=CPAP_TidalVolume;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration);
//Waveform *w=new Waveform(edf.startdate,code,edf.edfsignals[s]->data,recs,duration,edf.edfsignals[s]->digital_minimum,edf.edfsignals[s]->digital_maximum);
//edf.edfsignals[s]->data=NULL; // so it doesn't get deleted when edf gets trashed.
//sess->AddWaveform(w);
} else if (edf.edfsignals[s]->label=="Leak") {
//EventList *a=new EventList(code,EVL_Waveform,es.gain,es.offset,es.physical_minimum,es.physical_maximum,rate);
//sess->eventlist[code].push_back(a);
//a->AddWaveform(edf.startdate,es.data,recs,duration);
es.physical_maximum=es.physical_minimum=0;
es.gain*=1000.0;
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
} else if (es.label=="Leak") {
code=CPAP_Leak;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration,1.0);
} else if (edf.edfsignals[s]->label=="FFL Index") {
// es.gain*=100.0;
//es.gain=1;//10.0;
es.offset=-0.5;
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
a->setMax(1);
a->setMin(0);
} else if (es.label=="FFL Index") {
code=CPAP_FlowLimitGraph;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration,1.0);
} else if (edf.edfsignals[s]->label=="Mask Pres") {
//es.gain=1;//10.0;
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
a->setMax(1);
a->setMin(0);
} else if (es.label=="Mask Pres") {
code=CPAP_Pressure;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration,50.0);
} else if (edf.edfsignals[s]->label=="Exp Press") {
//es.gain=1;
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
} else if (es.label=="Exp Press") {
code=CPAP_ExpPressure;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration,50.0);
} else if (edf.edfsignals[s]->label=="") {
EventList *a=ToTimeDelta(sess,edf,es, code,recs,duration,0,0);
} else if (es.label=="") {
if (emptycnt==0) {
code=ResMed_Empty1;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration,1.0);
ToTimeDelta(sess,edf,es, code,recs,duration);
} else if (emptycnt==1) {
code=ResMed_Empty2;
ToTimeDelta(sess,edf,edf.edfsignals[s]->data, code,recs,duration,1.0);
ToTimeDelta(sess,edf,es, code,recs,duration);
} else {
qDebug() << "Unobserved Empty Signal " << edf.edfsignals[s]->label;
qDebug() << "Unobserved Empty Signal " << es.label;
}
emptycnt++;
} else {
qDebug() << "Unobserved Signal " << edf.edfsignals[s]->label;
qDebug() << "Unobserved Signal " << es.label;
}
}
return true;

View File

@ -45,10 +45,12 @@ public:
QString label;
QString transducer_type;
QString physical_dimension;
long physical_minimum;
long physical_maximum;
long digital_minimum;
long digital_maximum;
double physical_minimum;
double physical_maximum;
double digital_minimum;
double digital_maximum;
double gain;
double offset;
QString prefiltering;
long nr;
QString reserved;
@ -68,10 +70,10 @@ public:
vector<EDFSignal *> edfsignals;
long GetNumSignals() { return num_signals; };
long GetNumDataRecords() { return num_data_records; };
double GetDuration() { return dur_data_record; };
QString GetPatient() { return patientident; };
long GetNumSignals() { return num_signals; }
long GetNumDataRecords() { return num_data_records; }
qint64 GetDuration() { return dur_data_record; }
QString GetPatient() { return patientident; }
bool Parse();
char *buffer;
EDFHeader header;
@ -101,9 +103,9 @@ public:
virtual ~ResmedLoader();
virtual int Open(QString & path,Profile *profile);
virtual int Version() { return resmed_data_version; };
virtual const QString & ClassName() { return resmed_class_name; };
void ToTimeDelta(Session *sess,EDFParser &edf, qint16 *data, MachineCode code, long recs,qint64 duration,EventDataType divisor=1);
virtual int Version() { return resmed_data_version; }
virtual const QString & ClassName() { return resmed_class_name; }
EventList * ToTimeDelta(Session *sess,EDFParser &edf, EDFSignal & es, MachineCode code, long recs,qint64 duration,EventDataType min=0,EventDataType max=0);
Machine *CreateMachine(QString serial,Profile *profile);

View File

@ -28,6 +28,8 @@ ZEOLoader::~ZEOLoader()
}
int ZEOLoader::Open(QString & path,Profile *profile)
{
profile=profile;
path=path;
// ZEO folder structure detection stuff here.
return 0; // number of machines affected

View File

@ -19,7 +19,6 @@
#include "SleepLib/machine_common.h"
#include "SleepLib/event.h"
#include "SleepLib/waveform.h"
#include "SleepLib/session.h"
#include "SleepLib/day.h"

View File

@ -93,7 +93,7 @@ extern map<CPAPMode,QString> CPAPModeNames;
enum MCDataType//:wxInt8
{ MC_bool=0, MC_int, MC_long, MC_float, MC_double, MC_string, MC_datetime };
typedef float EventDataType;
typedef qint16 EventStoreType;
#endif // MACHINE_COMMON_H

View File

@ -19,8 +19,6 @@ License: GPL
#include "preferences.h"
//const QString AppName="SleepyHead";
const QString & getUserName()
{
static QString userName;
@ -29,7 +27,6 @@ const QString & getUserName()
if (userName.isEmpty()) {
userName="Windows User";
// FIXME: I DONT KNOW QT'S WINDOWS DEFS
#if defined (Q_WS_WIN32)
#if defined(UNICODE)
if ( qWinVersion() & Qt::WV_NT_based ) {

View File

@ -9,6 +9,7 @@
#include "math.h"
#include <QDir>
#include <QDebug>
#include <QMetaType>
#include <vector>
#include <algorithm>
@ -23,263 +24,42 @@ Session::Session(Machine * m,SessionID session)
s_session=session;
s_changed=false;
s_events_loaded=false;
s_waves_loaded=false;
_first_session=true;
s_first=s_last=0;
s_wavefile="";
s_eventfile="";
}
Session::~Session()
{
TrashEvents();
TrashWaveforms();
}
double Session::min_event_field(MachineCode mc,int field)
{
if (events.find(mc)==events.end()) return 0;
bool first=true;
double min=0;
vector<Event *>::iterator i;
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
if (field>=(*i)->e_fields) {
qWarning() << "Invalid Event field in Session::min_event_field";
return 0;
}
if (first) {
first=false;
min=(*(*i))[field];
} else {
if (min>(*(*i))[field]) min=(*(*i))[field];
}
}
return min;
}
double Session::max_event_field(MachineCode mc,int field)
{
if (events.find(mc)==events.end()) return 0;
bool first=true;
double max=0;
vector<Event *>::iterator i;
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
if (field>=(*i)->e_fields) {
qWarning() << "Invalid Event field in Session::max_event_field";
return 0;
}
if (first) {
first=false;
max=(*(*i))[field];
} else {
if (max<(*(*i))[field]) max=(*(*i))[field];
}
}
return max;
}
double Session::sum_event_field(MachineCode mc,int field)
{
if (events.find(mc)==events.end()) return 0;
double sum=0;
vector<Event *>::iterator i;
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
if (field>=(*i)->e_fields) {
qWarning() << "Invalid Event field in Session::sum_event_field";
return 0;
}
sum+=(*(*i))[field];
}
return sum;
}
double Session::avg_event_field(MachineCode mc,int field)
{
if (events.find(mc)==events.end()) return 0;
double sum=0;
int cnt=0;
vector<Event *>::iterator i;
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
if (field>=(*i)->e_fields) {
qWarning() << "Invalid Event field in Session::avg_event_field";
return 0;
}
sum+=(*(*i))[field];
cnt++;
}
return sum/cnt;
}
bool sortfunction (double i,double j) { return (i<j); }
double Session::percentile(MachineCode mc,int field,double percent)
{
if (events.find(mc)==events.end()) return 0;
vector<EventDataType> array;
vector<Event *>::iterator e;
for (e=events[mc].begin(); e!=events[mc].end(); e++) {
Event & ev = *(*e);
array.push_back(ev[field]);
}
std::sort(array.begin(),array.end(),sortfunction);
int size=array.size();
double i=size*percent;
double t;
double q=modf(i,&t);
int j=t;
if (j>=size-1) return array[j];
double a=array[j-1];
double b=array[j];
if (a==b) return a;
//double c=(b-a);
//double d=c*q;
return a;//array[j]+q;
}
double Session::weighted_avg_event_field(MachineCode mc,int field)
{
if (events.find(mc)==events.end()) return 0;
int cnt=0;
bool first=true;
qint64 last;
int lastval=0,val;
const int max_slots=2600;
qint64 vtime[max_slots]={0};
double mult;
if ((mc==CPAP_Pressure) || (mc==CPAP_EAP) || (mc==CPAP_IAP) | (mc==CPAP_PS)) {
mult=10.0;
} else mult=10.0;
vector<Event *>::iterator i;
for (i=events[mc].begin(); i!=events[mc].end(); i++) {
Event & e =(*(*i));
val=e[field]*mult;
if (field>=(*i)->e_fields) {
qWarning() << "Invalid Event field in Session::weighted_avg_event_field";
return 0;
}
if (first) {
first=false;
} else {
int d=(e.e_time-last)/1000L;
if (lastval>max_slots) {
qWarning("max_slots to small in Session::weighted_avg_event_fied()");
return 0;
}
vtime[lastval]+=d;
}
cnt++;
last=e.e_time;
lastval=val;
}
qint64 total=0;
for (int i=0; i<max_slots; i++) total+=vtime[i];
//double hours=total.GetSeconds().GetLo()/3600.0;
qint64 s0=0,s1=0,s2=0;
if (total==0) return 0;
for (int i=0; i<max_slots; i++) {
if (vtime[i] > 0) {
s0=vtime[i];
s1+=i*s0;
s2+=s0;
}
}
double j=double(s1)/double(total);
return j/mult;
}
void Session::AddEvent(Event * e)
{
events[e->code()].push_back(e);
if (s_first) {
if (e->time()<s_first) s_first=e->time();
if (e->time()>s_last) s_last=e->time();
} else {
s_first=s_last=e->time();
//_first_session=false;
}
}
void Session::AddWaveform(Waveform *w)
{
waveforms[w->code()].push_back(w);
if (s_last) {
if (w->start()<s_first) s_first=w->start();
if (w->end()>s_last) s_last=w->end();
} else {
s_first=w->start();
s_last=w->end();
}
// Could parse the flow data for Breaths per minute info here..
}
void Session::TrashEvents()
// Trash this sessions Events and release memory.
{
map<MachineCode,vector<Event *> >::iterator i;
vector<Event *>:: iterator j;
for (i=events.begin(); i!=events.end(); i++) {
map<MachineCode,vector<EventList *> >::iterator i;
vector<EventList *>::iterator j;
for (i=eventlist.begin(); i!=eventlist.end(); i++) {
for (j=i->second.begin(); j!=i->second.end(); j++) {
delete *j;
}
}
events.clear();
eventlist.clear();
}
void Session::TrashWaveforms()
// Trash this sessions Waveforms and release memory.
{
map<MachineCode,vector<Waveform *> >::iterator i;
vector<Waveform *>:: iterator j;
for (i=waveforms.begin(); i!=waveforms.end(); i++) {
for (j=i->second.begin(); j!=i->second.end(); j++) {
delete *j;
}
}
waveforms.clear();
}
//const int max_pack_size=128;
bool Session::OpenEvents() {
if(s_events_loaded)
if (s_events_loaded)
return true;
bool b;
b=LoadEvents(s_eventfile);
if (!b) {
qWarning() << "Error Unkpacking Events" << s_eventfile;
return false;
}
s_events_loaded=b;
return b;
};
bool Session::OpenWaveforms() {
if (s_waves_loaded)
return true;
bool b;
b=LoadWaveforms(s_wavefile);
if (!b) {
qWarning() << "Error Unkpacking Wavefile" << s_wavefile;
}
s_waves_loaded=b;
return b;
return s_events_loaded=true;
};
bool Session::Store(QString path)
@ -297,10 +77,8 @@ bool Session::Store(QString path)
bool a;
a=StoreSummary(base+".000"); // if actually has events
//qDebug() << " Summary done";
if (events.size()>0) StoreEvents(base+".001");
if (eventlist.size()>0) StoreEvents(base+".001");
//qDebug() << " Events done";
if (waveforms.size()>0) StoreWaveforms(base+".002");
//qDebug() << " Waveform done";
if (a) {
s_changed=false;
}
@ -318,6 +96,7 @@ bool IsPlatformLittleEndian()
bool Session::StoreSummary(QString filename)
{
QFile file(filename);
file.open(QIODevice::WriteOnly);
@ -343,21 +122,23 @@ bool Session::StoreSummary(QString filename)
for (i=summary.begin(); i!=summary.end(); i++) {
MachineCode mc=i->first;
QVariant::Type type=i->second.type(); // Urkk.. this is a mess.
if (type==QVariant::Bool) {
QMetaType::Type type=(QMetaType::Type)i->second.type(); // Urkk.. this is a mess.
if (type==QMetaType::Bool) {
mctype[mc]=MC_bool;
} else if (type==QVariant::Int) {
} else if (type==QMetaType::Int) {
mctype[mc]=MC_int;
} else if (type==QVariant::LongLong) {
} else if (type==QMetaType::LongLong) {
mctype[mc]=MC_long;
} else if (type==QVariant::Double) {
} else if (type==QMetaType::Double) {
mctype[mc]=MC_double;
} else if (type==QVariant::String) {
} else if (type==QMetaType::Float) {
mctype[mc]=MC_float;
} else if (type==QMetaType::QString) {
mctype[mc]=MC_string;
} else if (type==QVariant::DateTime) {
} else if (type==QMetaType::QDateTime) {
mctype[mc]=MC_datetime;
} else {
QString t=i->second.typeToName(type);
QString t=i->second.typeToName((QVariant::Type)type);
qWarning() << "Error in Session->StoreSummary: Can't pack variant type " << t;
return false;
//exit(1);
@ -376,6 +157,9 @@ bool Session::StoreSummary(QString filename)
out << (qint64)i->second.toLongLong();
} else if (mctype[mc]==MC_double) {
out << (double)i->second.toDouble();
} else if (mctype[mc]==MC_float) {
float f=(float)i->second.toDouble(); // check me.
out << f;
} else if (mctype[mc]==MC_string) {
out << i->second.toString();
} else if (mctype[mc]==MC_datetime) {
@ -460,6 +244,10 @@ bool Session::LoadSummary(QString filename)
double dl;
in >> dl;
summary[mc]=(double)dl;
} else if (mctype[mc]==MC_float) {
float fl;
in >> fl;
summary[mc]=(float)fl;
} else if (mctype[mc]==MC_string) {
QString s;
in >> s;
@ -488,50 +276,56 @@ bool Session::StoreEvents(QString filename)
out << (quint16)1; // File type 1 == Event
out << (quint16)0; // File Version
quint32 starttime=s_first/1000L;
quint32 duration=(s_last-s_first)/1000L;
out << s_first;
out << s_last;
out << starttime;
out << duration;
out << (qint16)events.size(); // Number of event categories
out << (qint16)eventlist.size(); // Number of event categories
map<MachineCode,vector<Event *> >::iterator i;
vector<Event *>::iterator j;
map<MachineCode,vector<EventList *> >::iterator i;
vector<EventList *>::iterator j;
for (i=events.begin(); i!=events.end(); i++) {
out << (qint16)i->first; // MachineID
out << (qint16)i->second.size(); // count of events in this category
j=i->second.begin();
out << (qint8)(*j)->fields(); // number of data fields in this event type
for (i=eventlist.begin(); i!=eventlist.end(); i++) {
out << (qint16)i->first; // MachineCode
out << (qint16)i->second.size();
for (unsigned j=0;j<i->second.size();j++) {
EventList &e=*i->second[j];
out << e.first();
out << e.last();
out << (qint32)e.count();
out << (qint8)e.type();
out << e.rate();
out << e.gain();
out << e.offset();
//if (!e.update_minmax()) {
out << e.min();
out << e.max();
//} else {
// out << (EventDataType)0;
// out << (EventDataType)0;
//}
}
}
qint64 t,last;
quint32 x;
for (i=eventlist.begin(); i!=eventlist.end(); i++) {
for (unsigned j=0;j<i->second.size();j++) {
EventList &e=*i->second[j];
for (int c=0;c<e.count();c++) {
out << e.raw(c);
}
if (e.type()!=EVL_Waveform) {
last=e.first();
for (int c=0;c<e.count();c++) {
t=e.time(c);
x=(t-last);
out << x;
last=e.time(c);
}
}
}
}
bool first;
EventDataType tf;
qint64 last=0,eventtime,delta;
for (i=events.begin(); i!=events.end(); i++) {
first=true;
for (j=i->second.begin(); j!=i->second.end(); j++) {
eventtime=(*j)->time();
if (first) {
out << (*j)->time();
first=false;
} else {
delta=eventtime-last;
if (delta>0xffffffff) {
qDebug("StoreEvent: Delta too big.. needed to use bigger value");
return false;
}
out << (quint32)delta;
}
for (int k=0; k<(*j)->fields(); k++) {
tf=(*(*j))[k];
out << tf;
}
last=eventtime;
}
}
//file.close();
return true;
}
@ -552,8 +346,6 @@ bool Session::LoadEvents(QString filename)
quint8 t8;
//qint16 i16;
// qint16 sumsize;
in >> t32; // Magic Number
if (t32!=magic) {
qWarning() << "Wrong Magic number in " << filename;
@ -573,187 +365,268 @@ bool Session::LoadEvents(QString filename)
in >> t16; // File Version
// dont give a crap yet..
in >> t32; // Start time
s_first=qint64(t32)*1000L;
in >> t32; // Duration // (16bit==Limited to 18 hours)
s_last=s_first+qint64(t32)*1000L;
in >> s_first;
in >> s_last;
qint16 evsize;
in >> evsize; // Summary size (number of Machine Code lists)
qint16 mcsize;
in >> mcsize; // Summary size (number of Machine Code lists)
map<MachineCode,qint16> mcsize;
map<MachineCode,qint16> mcfields;
MachineCode code;
qint64 ts1,ts2;
qint32 evcount;
EventListType elt;
EventDataType rate,gain,offset,mn,mx;
qint16 size2;
vector<MachineCode> mcorder;
vector<qint16> sizevec;
for (int i=0;i<mcsize;i++) {
in >> t16;
code=(MachineCode)t16;
mcorder.push_back(code);
in >> size2;
sizevec.push_back(size2);
for (int j=0;j<size2;j++) {
in >> ts1;
//UpdateFirst(ts1);
in >> ts2;
//UpdateLast(ts2);
in >> evcount;
in >> t8;
elt=(EventListType)t8;
in >> rate;
in >> gain;
in >> offset;
in >> mn;
in >> mx;
EventList *elist=new EventList(code,elt,gain,offset,mn,mx,rate);
MachineCode mc;
for (int i=0; i<evsize; i++) {
in >> t16; // MachineCode
mc=(MachineCode)t16;
mcorder.push_back(mc);
in >> t16; // Count of this Event
mcsize[mc]=t16;
in >> t8; // Type
mcfields[mc]=t8;
eventlist[code].push_back(elist);
elist->m_count=evcount;
elist->m_first=ts1;
elist->m_last=ts2;
}
}
for (int i=0; i<evsize; i++) {
mc=mcorder[i];
EventStoreType t;
qint64 last;
quint32 x;
for (int i=0;i<mcsize;i++) {
code=mcorder[i];
size2=sizevec[i];
for (int j=0;j<size2;j++) {
EventList &evec=*eventlist[code][j];
evec.m_data.resize(evec.m_count);
for (int c=0;c<evec.m_count;c++) {
in >> t;
evec.m_data[c]=t;
}
last=evec.first();
if (evec.type()!=EVL_Waveform) {
evec.m_time.resize(evec.m_count);
for (int c=0;c<evec.m_count;c++) {
in >> x;
last+=x;
evec.m_time[c]=last;
}
}
}
}
return true;
}
EventDataType Session::min(MachineCode code)
{
if (eventlist.find(code)==eventlist.end())
return 0;
vector<EventList *> & evec=eventlist[code];
bool first=true;
qint64 d;
events[mc].clear();
for (int e=0; e<mcsize[mc]; e++) {
EventDataType min,t1;
for (unsigned i=0;i<evec.size();i++) {
t1=evec[i]->min();
if (t1==evec[i]->max()) continue;
if (first) {
in >> d; // Timestamp
min=t1;
first=false;
} else {
in >> t32; // Time Delta
d=d+t32;
}
EventDataType ED[max_number_event_fields];
for (int c=0; c<mcfields[mc]; c++) {
in >> ED[c]; // Data Fields in float format
}
Event *ev=new Event(d,mc,ED,mcfields[mc]);
AddEvent(ev);
if (min>t1) min=t1;
}
}
return true;
return min;
}
bool Session::StoreWaveforms(QString filename)
EventDataType Session::max(MachineCode code)
{
QFile file(filename);
file.open(QIODevice::WriteOnly);
QDataStream out(&file);
out.setVersion(QDataStream::Qt_4_6);
quint16 t16;
out << (quint32)magic; // Magic Number
out << (quint32)s_machine->id(); // Machine ID
out << (quint32)s_session; // This session's ID
out << (quint16)2; // File type 2 == Waveform
out << (quint16)0; // File Version
quint32 starttime=s_first/1000L;
quint32 duration=(s_last-s_first)/1000L;
out << starttime;
out << duration;
out << (qint16)waveforms.size(); // Number of different waveforms
map<MachineCode,vector<Waveform *> >::iterator i;
vector<Waveform *>::iterator j;
for (i=waveforms.begin(); i!=waveforms.end(); i++) {
//qDebug() << "Storing Waveform" << zz++ << filename;
out << (quint16)i->first; // Machine Code
t16=i->second.size();
out << t16; // Number of (hopefully non-linear) waveform chunks
for (j=i->second.begin(); j!=i->second.end(); j++) {
//qDebug() << "Storing Waveform Chunk" << chnk++;
Waveform &w=*(*j);
// 64bit number..
out << (qint64)w.start(); // Start time of first waveform chunk
//qint32 samples;
//double seconds;
out << (qint32)w.samples(); // Total number of samples
out << (qint64)w.duration(); // Total number of seconds
out << (SampleFormat)w.min();
out << (SampleFormat)w.max();
out << (qint8)sizeof(SampleFormat); // Bytes per sample
out << (qint8)0; // signed.. all samples for now are signed 16bit.
//t8=0; // 0=signed, 1=unsigned, 2=float
// followed by sample data.
//qDebug() << "Writing " << (*j)->samples() << "samples";
for (int k=0; k<(*j)->samples(); k++) out << w[k];
if (eventlist.find(code)==eventlist.end())
return 0;
vector<EventList *> & evec=eventlist[code];
bool first=true;
EventDataType max,t1;
for (unsigned i=0;i<evec.size();i++) {
t1=evec[i]->max();
if (t1==evec[i]->min()) continue;
if (first) {
max=t1;
first=false;
} else {
if (max<t1) max=t1;
}
}
return true;
return max;
}
bool Session::LoadWaveforms(QString filename)
qint64 Session::first(MachineCode code)
{
if (filename.isEmpty()) return false;
QFile file(filename);
if (!file.open(QIODevice::ReadOnly)) {
qDebug() << "Couldn't open file" << filename;
return false;
}
QDataStream in(&file);
in.setVersion(QDataStream::Qt_4_6);
quint32 t32;
quint16 t16;
quint8 t8;
in >>t32; // Magic Number
if (t32!=magic) {
qDebug() << "Wrong magic in " << filename;
return false;
}
in >> t32; // MachineID
in >> t32; // Sessionid;
s_session=t32;
in >> t16; // File Type
if (t16!=2) {
qDebug() << "Wrong File Type in " << filename;
return false;
}
in >> t16; // File Version
// dont give a crap yet..
in >> t32; // Start time
s_first=qint64(t32)*1000;
in >> t32; // Duration // (16bit==Limited to 18 hours)
s_last=s_first+qint64(t32)*1000;
quint16 wvsize;
in >> wvsize; // Number of waveforms
MachineCode mc;
qint64 date;
qint64 seconds;
qint32 samples;
int chunks;
SampleFormat min,max;
for (int i=0; i<wvsize; i++) {
in >> t16; // Machine Code
mc=(MachineCode)t16;
in >> t16; // Number of waveform Chunks
chunks=t16;
for (int i=0; i<chunks; i++) {
in >> date; // Waveform DateTime
in >> samples; // Number of samples
in >> seconds; // Duration in seconds
in >> min; // Min value
in >> max; // Min value
in >> t8; // sample size in bytes
in >> t8; // Number of samples (?? what did I mean by this)
SampleFormat *data=new SampleFormat [samples];
for (int k=0; k<samples; k++) {
in >> data[k]; // Individual Samples;
}
Waveform *w=new Waveform(date,mc,data,samples,seconds,min,max);
AddWaveform(w);
if (eventlist.find(code)==eventlist.end())
return 0;
vector<EventList *> & evec=eventlist[code];
bool first=true;
qint64 min,t1;
for (unsigned i=0;i<evec.size();i++) {
t1=evec[i]->first();
if (first) {
min=t1;
first=false;
} else {
if (min>t1) min=t1;
}
}
return true;
return min;
}
qint64 Session::last(MachineCode code)
{
if (eventlist.find(code)==eventlist.end())
return 0;
vector<EventList *> & evec=eventlist[code];
bool first=true;
qint64 max,t1;
for (unsigned i=0;i<evec.size();i++) {
t1=evec[i]->last();
if (first) {
max=t1;
first=false;
} else {
if (max<t1) max=t1;
}
}
return max;
}
int Session::count(MachineCode code)
{
if (eventlist.find(code)==eventlist.end())
return 0;
vector<EventList *> & evec=eventlist[code];
int sum=0;
for (unsigned i=0;i<evec.size();i++) {
sum+=evec[i]->count();
}
return sum;
}
double Session::sum(MachineCode mc)
{
if (eventlist.find(mc)==eventlist.end()) return 0;
vector<EventList *> & evec=eventlist[mc];
double sum=0;
for (unsigned i=0;i<evec.size();i++) {
for (int j=0;j<evec[i]->count();j++) {
sum+=evec[i]->data(j);
}
}
return sum;
}
EventDataType Session::avg(MachineCode mc)
{
if (eventlist.find(mc)==eventlist.end()) return 0;
double cnt=count(mc);
if (cnt==0) return 0;
EventDataType val=sum(mc)/cnt;
return val;
}
bool sortfunction (double i,double j) { return (i<j); }
EventDataType Session::percentile(MachineCode mc,double percent)
{
if (eventlist.find(mc)==eventlist.end()) return 0;
vector<EventDataType> array;
vector<EventList *> & evec=eventlist[mc];
for (unsigned i=0;i<evec.size();i++) {
for (int j=0;j<evec[i]->count();j++) {
array.push_back(evec[i]->data(j));
}
}
std::sort(array.begin(),array.end(),sortfunction);
int size=array.size();
if (!size) return 0;
double i=size*percent;
double t;
modf(i,&t);
int j=t;
//if (j>=size-1) return array[j];
return array[j];
}
EventDataType Session::weighted_avg(MachineCode mc)
{
if (eventlist.find(mc)==eventlist.end()) return 0;
int cnt=0;
bool first=true;
qint64 last;
int lastval=0,val;
const int max_slots=4096;
qint64 vtime[max_slots]={0};
double mult=10.0;
//if ((mc==CPAP_Pressure) || (mc==CPAP_EAP) || (mc==CPAP_IAP) | (mc==CPAP_PS)) {
// mult=10.0;
//} else mult=10.0;
// vector<Event *>::iterator i;
vector<EventList *> & evec=eventlist[mc];
for (unsigned i=0;i<evec.size();i++) {
for (int j=0;j<evec[i]->count();j++) {
val=evec[i]->data(j)*mult;
if (first) {
first=false;
} else {
int d=(evec[i]->time(j)-last)/1000L;
if (lastval>max_slots) {
qWarning("max_slots to small in Session::weighted_avg()");
return 0;
}
vtime[lastval]+=d;
}
cnt++;
last=evec[i]->time(j);
lastval=val;
}
}
qint64 total=0;
for (int i=0; i<max_slots; i++) total+=vtime[i];
//double hours=total.GetSeconds().GetLo()/3600.0;
qint64 s0=0,s1=0,s2=0;
if (total==0) return 0;
for (int i=0; i<max_slots; i++) {
if (vtime[i] > 0) {
s0=vtime[i];
s1+=i*s0;
s2+=s0;
}
}
double j=double(s1)/double(total);
return j/mult;
}

View File

@ -9,31 +9,27 @@
#define SESSION_H
#include <QDebug>
#include "SleepLib/machine.h"
#include "SleepLib/machine.h"
#include "SleepLib/event.h"
class EventList;
class Machine;
class Session
{
public:
Session(Machine *,SessionID);
virtual ~Session();
void AddEvent(Event *e);
void AddWaveform(Waveform *w);
bool Store(QString path);
bool StoreSummary(QString filename);
bool StoreEvents(QString filename);
bool StoreWaveforms(QString filename);
//bool Load(QString path);
bool LoadSummary(QString filename);
bool LoadEvents(QString filename);
bool LoadWaveforms(QString filename);
bool OpenEvents();
bool OpenWaveforms();
void TrashEvents();
void TrashWaveforms();
const SessionID & session() {
return s_session;
@ -64,16 +60,6 @@ public:
double t=(s_last-s_first)/3600000.0;
return t;
};
int count_events(MachineCode mc) {
if (events.find(mc)==events.end()) return 0;
return events[mc].size();
};
double min_event_field(MachineCode mc,int field);
double max_event_field(MachineCode mc,int field);
double sum_event_field(MachineCode mc,int field);
double avg_event_field(MachineCode mc,int field);
double weighted_avg_event_field(MachineCode mc,int field);
double percentile(MachineCode mc,int field,double percentile);
map<MachineCode,QVariant> summary;
void SetChanged(bool val) {
@ -84,13 +70,26 @@ public:
bool IsChanged() {
return s_changed;
};
map<MachineCode,vector<Event *> > events;
map<MachineCode,vector<Waveform *> > waveforms;
bool IsLoneSession() { return s_lonesession; };
void SetLoneSession(bool b) { s_lonesession=b; };
void SetEventFile(QString & filename) { s_eventfile=filename; };
void SetWaveFile(QString & filename) { s_wavefile=filename; };
map<MachineCode,vector<EventList *> > eventlist;
bool IsLoneSession() { return s_lonesession; }
void SetLoneSession(bool b) { s_lonesession=b; }
void SetEventFile(QString & filename) { s_eventfile=filename; }
void SetWaveFile(QString & filename) { s_wavefile=filename; }
inline void UpdateFirst(qint64 v) { if (!s_first) s_first=v; else if (s_first>v) s_first=v; }
inline void UpdateLast(qint64 v) { if (!s_last) s_last=v; else if (s_last<v) s_last=v; }
EventDataType min(MachineCode code);
EventDataType max(MachineCode code);
qint64 first(MachineCode code);
qint64 last(MachineCode code);
int count(MachineCode code);
double sum(MachineCode mc);
EventDataType avg(MachineCode mc);
EventDataType weighted_avg(MachineCode mc);
EventDataType percentile(MachineCode mc,double percentile);
protected:
SessionID s_session;

View File

@ -1,20 +0,0 @@
/********************************************************************
SleepLib Waveform Class Implementation
Copyright (c)2011 Mark Watkins <jedimark@users.sourceforge.net>
License: GPL
*********************************************************************/
#include "waveform.h"
Waveform::Waveform(qint64 time,MachineCode code, SampleFormat *data,int samples,qint64 duration,SampleFormat min, SampleFormat max)
:w_time(time),w_code(code),w_data(data),w_samples(samples),w_duration(duration)
{
w_totalspan=duration;
w_samplespan=duration/samples;
Min=min;
Max=max;
}
Waveform::~Waveform()
{
delete [] w_data;
}

View File

@ -1,61 +0,0 @@
/********************************************************************
SleepLib Waveform Header
This stuff contains the base calculation smarts
Copyright (c)2011 Mark Watkins <jedimark@users.sourceforge.net>
License: GPL
*********************************************************************/
#ifndef WAVEFORM_H
#define WAVEFORM_H
#include <QDateTime>
#include "machine_common.h"
typedef qint16 SampleFormat;
class Waveform
{
friend class Session;
public:
Waveform(qint64 time,MachineCode code,SampleFormat * data,int samples,qint64 duration,SampleFormat min, SampleFormat max);
~Waveform();
SampleFormat operator[](int i) {
if (i<w_samples) return w_data[i];
else return 0;
};
qint64 start() {
return w_time;
};
qint64 end() {
return w_time+w_totalspan;
};
MachineCode code() {
return w_code;
};
int samples() {
return w_samples;
};
qint64 duration() {
return w_duration;
};
SampleFormat min() {
return Min;
};
SampleFormat max() {
return Max;
};
SampleFormat *GetBuffer() { return w_data; };
protected:
qint64 w_time;
MachineCode w_code;
SampleFormat * w_data;
qint32 w_samples;
qint64 w_duration;
SampleFormat Min,Max;
qint64 w_totalspan;
qint64 w_samplespan;
};
#endif // WAVEFORM_H

View File

@ -37,7 +37,6 @@ SOURCES += main.cpp\
SleepLib/event.cpp \
SleepLib/session.cpp \
SleepLib/day.cpp \
SleepLib/waveform.cpp \
Graphs/graphwindow.cpp \
Graphs/graphlayer.cpp \
Graphs/graphdata.cpp \
@ -88,7 +87,6 @@ HEADERS += \
SleepLib/machine_common.h \
SleepLib/session.h \
SleepLib/day.h \
SleepLib/waveform.h \
Graphs/graphwindow.h \
Graphs/graphlayer.h \
Graphs/graphdata.h \

276
daily.cpp
View File

@ -12,10 +12,10 @@
#include <QColorDialog>
#include <QBuffer>
#include <QPixmap>
#include <QMessageBox>
#include "SleepLib/session.h"
#include "Graphs/graphdata_custom.h"
#include "Graphs/gLineChart.h"
#include "Graphs/gLineOverlay.h"
#include "Graphs/gFlagsLine.h"
#include "Graphs/gFooBar.h"
@ -35,8 +35,8 @@ Daily::Daily(QWidget *parent,QGLWidget * shared) :
QString prof=pref["Profile"].toString();
profile=Profiles::Get(prof);
if (!profile) {
qWarning("Couldn't get profile.. Have to abort!");
abort();
QMessageBox::critical(this,"Profile Error",QString("Couldn't get profile '%1'.. Have to abort!").arg(pref["Profile"].toString()));
exit(-1);
}
gSplitter=new QSplitter(Qt::Vertical,ui->scrollArea);
@ -57,6 +57,11 @@ Daily::Daily(QWidget *parent,QGLWidget * shared) :
PTB=new gGraphWindow(gSplitter,tr("Patient Trig Breaths"),SF);
PULSE=new gGraphWindow(gSplitter,tr("Pulse & SpO2"),SF);
TAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
TAP_EAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
TAP_IAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
G_AHI=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
/*QGLFormat fmt;
fmt.setDepth(false);
fmt.setDirectRendering(false);
@ -66,23 +71,6 @@ Daily::Daily(QWidget *parent,QGLWidget * shared) :
//fmt.setDefaultFormat(fmt);
offscreen_context=new QGLContext(fmt); */
AddCPAPData(flags[0]=new FlagData(CPAP_CSR,1,0));
AddCPAPData(flags[1]=new FlagData(CPAP_ClearAirway));
AddCPAPData(flags[2]=new FlagData(CPAP_Obstructive));
AddCPAPData(flags[3]=new FlagData(CPAP_Hypopnea));
AddCPAPData(flags[4]=new FlagData(CPAP_FlowLimit));
AddCPAPData(flags[5]=new FlagData(CPAP_VSnore));
AddCPAPData(flags[6]=new FlagData(CPAP_RERA));
AddCPAPData(flags[7]=new FlagData(PRS1_PressurePulse));
AddCPAPData(flags[8]=new FlagData(PRS1_Unknown0E));
AddCPAPData(flags[9]=new FlagData(CPAP_Apnea));
AddCPAPData(flags[10]=new FlagData(CPAP_Snore));
TAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
TAP_EAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
TAP_IAP=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
G_AHI=new gGraphWindow(NULL,"",(QGLWidget* )NULL);
SF->SetLeftMargin(SF->GetLeftMargin()+gYAxis::Margin);
SF->SetBlockZoom(true);
@ -90,159 +78,133 @@ Daily::Daily(QWidget *parent,QGLWidget * shared) :
SF->setMinimumHeight(160);
fg=new gFlagsGroup();
fg->AddLayer(new gFlagsLine(flags[0],QColor("light green"),"CSR"));
fg->AddLayer(new gFlagsLine(flags[1],QColor("purple"),"CA",true));
fg->AddLayer(new gFlagsLine(flags[2],QColor("#40c0ff"),"OA",true));
fg->AddLayer(new gFlagsLine(flags[3],QColor("blue"),"H",true));
fg->AddLayer(new gFlagsLine(flags[4],QColor("black"),"FL"));
fg->AddLayer(new gFlagsLine(flags[6],QColor("gold"),"RE"));
fg->AddLayer(new gFlagsLine(flags[5],QColor("red"),"VS"));
fg->AddLayer(new gFlagsLine(flags[8],QColor("dark green"),"U0E"));
fg->AddLayer(new gFlagsLine(flags[9],QColor("dark green"),"A"));
//fg->AddLayer(new gFlagsLine(flags[10],QColor("red"),"VS2"));
fg->AddLayer(new gFlagsLine(CPAP_CSR,QColor("light green"),"CSR",false,FLT_Span));
fg->AddLayer(new gFlagsLine(CPAP_ClearAirway,QColor("purple"),"CA",true));
fg->AddLayer(new gFlagsLine(CPAP_Obstructive,QColor("#40c0ff"),"OA",true));
fg->AddLayer(new gFlagsLine(CPAP_Hypopnea,QColor("blue"),"H",true));
fg->AddLayer(new gFlagsLine(CPAP_FlowLimit,QColor("black"),"FL"));
fg->AddLayer(new gFlagsLine(CPAP_RERA,QColor("gold"),"RE"));
fg->AddLayer(new gFlagsLine(CPAP_VSnore,QColor("red"),"VS"));
//fg->AddLayer(AddCPAP(new gFlagsLine(flags[8],QColor("dark green"),"U0E"));
fg->AddLayer(new gFlagsLine(CPAP_Apnea,QColor("dark green"),"A"));
//fg->AddLayer(AddCPAP(new gFlagsLine(flags[10],QColor("red"),"VS2"));
SF->AddLayer(fg);
SF->AddLayer(AddCPAP(fg));
// SF Foobar must go last
SF->AddLayer(new gFooBar(10,QColor("orange"),QColor("dark grey"),true));
AddCPAPData(pressure_iap=new EventData(CPAP_IAP));
AddCPAPData(pressure_eap=new EventData(CPAP_EAP));
AddCPAPData(prd=new EventData(CPAP_Pressure));
//pressure_eap->ForceMinY(0);
//pressure_eap->ForceMaxY(30);
PRD->AddLayer(new gXAxis());
PRD->AddLayer(new gYAxis());
//PRD->AddLayer(new gFooBar());
bool square=true;
PRD->AddLayer(new gLineChart(prd,QColor("dark green"),4096,false,false,square));
PRD->AddLayer(new gLineChart(pressure_iap,Qt::blue,4096,false,true,square));
PRD->AddLayer(new gLineChart(pressure_eap,Qt::red,4096,false,true,square));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_Pressure,QColor("dark green"),square)));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_EAP,Qt::blue,square)));
PRD->AddLayer(AddCPAP(new gLineChart(CPAP_IAP,Qt::red,square)));
PRD->setMinimumHeight(150);
AddCPAPData(leak=new EventData(CPAP_Leak,0));
LEAK->AddLayer(new gXAxis());
LEAK->AddLayer(new gYAxis());
//LEAK->AddLayer(new gFooBar());
LEAK->AddLayer(new gLineChart(leak,QColor("purple"),65536,false,false,true));
LEAK->AddLayer(AddCPAP(new gLineChart(CPAP_Leak,QColor("purple"),true)));
LEAK->setMinimumHeight(150);
AddCPAPData(mp=new WaveData(CPAP_MaskPressure,1000000)); //FlowRate
gYAxis *y=new gYAxis();
y->SetScale(1.0/50.0);
MP->AddLayer(y);
MP->AddLayer(new gYAxis());
MP->AddLayer(new gXAxis());
gLineChart *g=new gLineChart(mp,Qt::blue,4000,true);
gLineChart *g=new gLineChart(CPAP_MaskPressure,Qt::blue,false);
AddCPAP(g);
g->ReportEmpty(true);
MP->AddLayer(g);
MP->setMinimumHeight(120);
MP->setMinimumHeight(150);
AddCPAPData(frw=new WaveData(CPAP_FlowRate,1000000)); //FlowRate
// Holy crap resmed stuff is huge..
//FRW->AddLayer(new gFooBar());
FRW->AddLayer(new gYAxis());
FRW->AddLayer(new gXAxis());
FRW->AddLayer(new gLineOverlayBar(flags[0],QColor("light green"),"CSR"));
// FRW->AddLayer(new gLineChart(mpw,Qt::blue,700000,true));
g=new gLineChart(frw,Qt::black,4000,true);
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_CSR,QColor("light green"),"CSR",LOT_Span)));
g=new gLineChart(CPAP_FlowRate,Qt::black,false);
g->ReportEmpty(true);
AddCPAP(g);
FRW->AddLayer(g);
FRW->AddLayer(new gLineOverlayBar(flags[3],QColor("blue"),"H"));
FRW->AddLayer(new gLineOverlayBar(flags[7],QColor("red"),"PR",LOT_Dot));
FRW->AddLayer(new gLineOverlayBar(flags[6],QColor("gold"),"RE"));
//FRW->AddLayer(new gLineOverlayBar(flags[9],QColor("dark green"),"U0E"));
FRW->AddLayer(new gLineOverlayBar(flags[5],QColor("red"),"VS"));
FRW->AddLayer(new gLineOverlayBar(flags[4],QColor("black"),"FL"));
FRW->AddLayer(new gLineOverlayBar(flags[2],QColor("#40c0ff"),"OA"));
FRW->AddLayer(new gLineOverlayBar(flags[1],QColor("purple"),"CA"));
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Hypopnea,QColor("blue"),"H")));
FRW->AddLayer(AddCPAP(new gLineOverlayBar(PRS1_PressurePulse,QColor("red"),"PR",LOT_Dot)));
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_RERA,QColor("gold"),"RE")));
//FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Unknown0E,QColor("dark green"),"U0E")));
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_VSnore,QColor("red"),"VS")));
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_FlowLimit,QColor("black"),"FL")));
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_Obstructive,QColor("#40c0ff"),"OA")));
FRW->AddLayer(AddCPAP(new gLineOverlayBar(CPAP_ClearAirway,QColor("purple"),"CA")));
FRW->setMinimumHeight(150);
FRW->setMinimumHeight(180);
AddCPAPData(snore=new EventData(CPAP_Snore,0));
SNORE->AddLayer(new gXAxis());
SNORE->AddLayer(new gYAxis());
SNORE->AddLayer(new gLineChart(snore,Qt::black,4096,false,false,true));
SNORE->AddLayer(AddCPAP(new gLineChart(CPAP_Snore,Qt::black,true)));
SNORE->setMinimumHeight(150);
AddCPAPData(flg=new EventData(CPAP_FlowLimitGraph,0));
FLG->AddLayer(new gXAxis());
FLG->AddLayer(new gYAxis());
FLG->AddLayer(new gLineChart(flg,Qt::black,4096,false,false,true));
FLG->AddLayer(AddCPAP(new gLineChart(CPAP_FlowLimitGraph,Qt::black,true)));
FLG->setMinimumHeight(150);
AddCPAPData(mv=new EventData(CPAP_MinuteVentilation));
MV->AddLayer(new gXAxis());
MV->AddLayer(new gYAxis());
MV->AddLayer(new gLineChart(mv,QColor(0x20,0x20,0x7f),65536,false,false,true));
MV->AddLayer(AddCPAP(new gLineChart(CPAP_MinuteVentilation,QColor(0x20,0x20,0x7f),true)));
MV->setMinimumHeight(150);
AddCPAPData(tv=new EventData(CPAP_TidalVolume));
TV->AddLayer(new gXAxis());
TV->AddLayer(new gYAxis());
TV->AddLayer(new gLineChart(tv,QColor(0x7f,0x20,0x20),65536,false,false,true));
TV->AddLayer(AddCPAP(new gLineChart(CPAP_TidalVolume,QColor(0x7f,0x20,0x20),true)));
TV->setMinimumHeight(150);
AddCPAPData(rr=new EventData(CPAP_RespiratoryRate));
RR->AddLayer(new gXAxis());
RR->AddLayer(new gYAxis());
RR->AddLayer(new gLineChart(rr,Qt::gray,65536,false,false,true));
RR->AddLayer(AddCPAP(new gLineChart(CPAP_RespiratoryRate,Qt::gray,true)));
RR->setMinimumHeight(150);
AddCPAPData(ptb=new EventData(CPAP_PatientTriggeredBreaths ));
PTB->AddLayer(new gXAxis());
PTB->AddLayer(new gYAxis());
PTB->AddLayer(new gLineChart(ptb,Qt::gray,65536,false,false,true));
PTB->AddLayer(AddCPAP(new gLineChart(CPAP_PatientTriggeredBreaths,Qt::gray,true)));
PTB->setMinimumHeight(150);
AddOXIData(pulse=new EventData(OXI_Pulse,0,65536,true));
//pulse->ForceMinY(40);
//pulse->ForceMaxY(120);
PULSE->AddLayer(new gXAxis());
PULSE->AddLayer(new gYAxis());
// PULSE->AddLayer(new gFooBar());
PULSE->AddLayer(new gLineChart(pulse,Qt::red,65536,false,false,true));
PULSE->AddLayer(AddOXI(new gLineChart(OXI_Pulse,Qt::red,true)));
PULSE->setMinimumHeight(150);
AddOXIData(spo2=new EventData(OXI_SPO2,0,65536,true));
//spo2->ForceMinY(60);
//spo2->ForceMaxY(100);
// SPO2=new gGraphWindow(gSplitter,tr("SpO2"),SF);
// SPO2->AddLayer(new gXAxis());
// SPO2->AddLayer(new gYAxis());
// SPO2->AddLayer(new gFooBar());
PULSE->AddLayer(new gLineChart(spo2,Qt::blue,65536,false,false,true));
PULSE->AddLayer(AddOXI(new gLineChart(OXI_SPO2,Qt::blue,true)));
// SPO2->setMinimumHeight(150);
// SPO2->LinkZoom(PULSE);
// PULSE->LinkZoom(SPO2);
// SPO2->hide();
PULSE->hide();
AddCPAPData(tap_eap=new TAPData(CPAP_EAP));
AddCPAPData(tap_iap=new TAPData(CPAP_IAP));
AddCPAPData(tap=new TAPData(CPAP_Pressure));
//AddCPAPData(tap_eap=new TAPData(CPAP_EAP));
//AddCPAPData(tap_iap=new TAPData(CPAP_IAP));
//AddCPAPData(tap=new TAPData(CPAP_Pressure));
//TAP->SetMargins(20,15,5,50);
TAP->SetMargins(0,0,0,0);
TAP->AddLayer(new gCandleStick(tap));
//TAP->SetMargins(0,0,0,0);
//TAP->AddLayer(new gCandleStick(tap));
//TAP->AddLayer(new gPieChart(tap));
TAP_EAP->SetMargins(0,0,0,0);
TAP_EAP->AddLayer(new gCandleStick(tap_eap));
//TAP_EAP->SetMargins(0,0,0,0);
//TAP_EAP->AddLayer(new gCandleStick(tap_eap));
TAP_IAP->SetMargins(0,0,0,0);
TAP_IAP->AddLayer(new gCandleStick(tap_iap));
//TAP_IAP->SetMargins(0,0,0,0);
//TAP_IAP->AddLayer(new gCandleStick(tap_iap));
G_AHI->SetMargins(0,0,0,0);
AddCPAPData(g_ahi=new AHIData());
//G_AHI->SetMargins(0,0,0,0);
//AddCPAPData(g_ahi=new AHIData());
//gCandleStick *l=new gCandleStick(g_ahi);
gPieChart *l=new gPieChart(g_ahi);
/*gPieChart *l=new gPieChart(g_ahi);
l->AddName(tr("H"));
l->AddName(tr("OA"));
l->AddName(tr("CA"));
@ -261,6 +223,11 @@ Daily::Daily(QWidget *parent,QGLWidget * shared) :
//G_AHI->setMaximumSize(2000,30);
//TAP->setMaximumSize(2000,30);
G_AHI->hide();
TAP->hide();
TAP_IAP->hide();
TAP_EAP->hide(); */
NoData=new QLabel(tr("No data"),gSplitter);
NoData->setAlignment(Qt::AlignCenter);
QFont font("FreeSans",20); //NoData->font();
@ -268,12 +235,6 @@ Daily::Daily(QWidget *parent,QGLWidget * shared) :
NoData->setFont(font);
NoData->hide();
G_AHI->hide();
TAP->hide();
TAP_IAP->hide();
TAP_EAP->hide();
gSplitter->addWidget(NoData);
gGraphWindow * graphs[]={SF,FRW,MP,MV,TV,PTB,RR,PRD,LEAK,FLG,SNORE};
@ -347,6 +308,7 @@ void Daily::UpdateEventsTree(QTreeWidget *tree,Day *day)
tree->clear();
if (!day) return;
return;
tree->setColumnCount(1); // 1 visible common.. (1 hidden)
QTreeWidgetItem *root=NULL;//new QTreeWidgetItem((QTreeWidget *)0,QStringList("Stuff"));
@ -354,13 +316,14 @@ void Daily::UpdateEventsTree(QTreeWidget *tree,Day *day)
map<MachineCode,int> mccnt;
int total_events=0;
for (vector<Session *>::iterator s=day->begin();s!=day->end();s++) {
map<MachineCode,vector<Event *> >::iterator m;
map<MachineCode,vector<EventList *> >::iterator m;
//QTreeWidgetItem * sroot;
for (m=(*s)->events.begin();m!=(*s)->events.end();m++) {
for (m=(*s)->eventlist.begin();m!=(*s)->eventlist.end();m++) {
MachineCode code=m->first;
if (code==CPAP_Leak) continue;
if (code==CPAP_RespiratoryRate) continue;
@ -388,27 +351,22 @@ void Daily::UpdateEventsTree(QTreeWidget *tree,Day *day)
} else {
mcr=mcroot[code];
}
for (vector<Event *>::iterator e=(*s)->events[code].begin();e!=(*s)->events[code].end();e++) {
qint64 t=(*e)->time();
for (unsigned z=0;z<m->second.size();z++) {
for (int o=0;o<m->second[z]->count();o++) {
qint64 t=m->second[z]->time(o);
if (code==CPAP_CSR) {
t-=((*(*e))[0]/2)*1000;
t-=(m->second[z]->data(o)/2)*1000;
}
QStringList a;
QDateTime d=QDateTime::fromMSecsSinceEpoch(t);
QString s=QString("#%1: %2").arg((int)++mccnt[code],(int)3,(int)10,QChar('0')).arg(d.toString("HH:mm:ss"));
if ((code==PRS1_Unknown0E) || (code==PRS1_Unknown10) || (code==PRS1_Unknown0B)) {
s.append(" "+QString::number((*(*e))[0]));
s.append(" "+QString::number((*(*e))[1]));
}
if ((code==PRS1_Unknown0E) || (code==PRS1_Unknown10)) {
s.append(" "+QString::number((*(*e))[2]));
}
QString s=QString("#%1: %2").arg((int)mccnt[code],(int)3,(int)10,QChar('0')).arg(d.toString("HH:mm:ss"));
a.append(s);
a.append(d.toString("yyyy-MM-dd HH:mm:ss"));
mcr->addChild(new QTreeWidgetItem(a));
}
}
}
}
int cnt=0;
for (map<MachineCode,QTreeWidgetItem *>::iterator m=mcroot.begin();m!=mcroot.end();m++) {
tree->insertTopLevelItem(cnt++,m->second);
@ -464,13 +422,33 @@ void Daily::Load(QDate date)
"<body leftmargin=0 rightmargin=0 topmargin=0 marginwidth=0 marginheight=0>"
"<table cellspacing=0 cellpadding=2 border=0 width='100%'>\n";
QString tmp;
const int gwwidth=240;
const int gwheight=25;
UpdateOXIGraphs(oxi);
UpdateCPAPGraphs(cpap);
UpdateEventsTree(ui->treeWidget,cpap);
for (unsigned i=0;i<Graphs.size();i++) {
if (Graphs[i]->isEmpty()) {
Graphs[i]->hide();
} else {
Graphs[i]->show();
}
}
if (!cpap && !oxi) {
NoData->setText(tr("No data for ")+date.toString(Qt::SystemLocaleLongDate));
NoData->show();
SF->hide();
} else {
NoData->hide();
SF->show();
}
gSplitter->layout();
gSplitter->update();
RedrawGraphs();
QString epr,modestr;
float iap90,eap90;
CPAPMode mode=MODE_UNKNOWN;
@ -495,9 +473,9 @@ void Daily::Load(QDate date)
float vsi=cpap->count(CPAP_VSnore)/cpap->hours();
float fli=cpap->count(CPAP_FlowLimit)/cpap->hours();
float p90=cpap->percentile(CPAP_Pressure,0,0.9);
eap90=cpap->percentile(CPAP_EAP,0,0.9);
iap90=cpap->percentile(CPAP_IAP,0,0.9);
float p90=cpap->percentile(CPAP_Pressure,0.9);
eap90=cpap->percentile(CPAP_EAP,0.9);
iap90=cpap->percentile(CPAP_IAP,0.9);
QString submodel=tr("Unknown Model");
//html+="<tr><td colspan=4 align=center><i>"+tr("Machine Information")+"</i></td></tr>\n";
@ -542,13 +520,13 @@ void Daily::Load(QDate date)
html+="</tr>\n<tr><td colspan=4 align=center><i>"+tr("Event Breakdown")+"</i></td></tr>\n";
if (1) {
G_AHI->setFixedSize(gwwidth,gwheight);
/* G_AHI->setFixedSize(gwwidth,gwheight);
QPixmap pixmap=G_AHI->renderPixmap(120,120,false); //gwwidth,gwheight,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html += "<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
html += "<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n"; */
}
html+="</table>"
"<table cellspacing=0 cellpadding=0 border=0 width='100%'>\n"
@ -595,12 +573,12 @@ void Daily::Load(QDate date)
html+="</td><td>"+a.sprintf("%.2f",cpap->summary_min(CPAP_SnoreMinimum));
html+="</td><td>"+a.sprintf("%.2f",cpap->summary_avg(CPAP_SnoreAverage));
html+="</td><td>"+a.sprintf("%.2f",cpap->summary_max(CPAP_SnoreMaximum))+("</td><tr>");
FRW->show();
/*FRW->show();
PRD->show();
LEAK->show();
SF->show();
SNORE->show();
MP->show();
MP->show(); */
} else {
@ -610,33 +588,23 @@ void Daily::Load(QDate date)
//TAP_EAP->Show(false);
//TAP_IAP->Show(false);
//G_AHI->Show(false);
FRW->hide();
/*FRW->hide();
PRD->hide();
LEAK->hide();
SF->hide();
SNORE->hide();
MP->hide();
MP->hide(); */
}
// Instead of doing this, check whether any data exists..
// and show based on this factor.
mv->isEmpty() ? MV->hide() : MV->show();
tv->isEmpty() ? TV->hide() : TV->show();
rr->isEmpty() ? RR->hide() : RR->show();
flg->isEmpty() ? FLG->hide() : FLG->show();
mp->isEmpty() ? MP->hide() : MP->show();
frw->isEmpty() ? FRW->hide() : FRW->show();
prd->isEmpty() && pressure_iap->isEmpty() ? PRD->hide() : PRD->show();
leak->isEmpty() ? LEAK->hide() : LEAK->show();
snore->isEmpty() ? SNORE->hide() : SNORE->show();
ptb->isEmpty() ? PTB->hide() : PTB->show();
bool merge_oxi_graphs=true;
if (!merge_oxi_graphs) {
spo2->isEmpty() ? SPO2->hide() : SPO2->show();
pulse->isEmpty() ? PULSE->hide() : PULSE->show();
//spo2->isEmpty() ? SPO2->hide() : SPO2->show();
//pulse->isEmpty() ? PULSE->hide() : PULSE->show();
} else {
pulse->isEmpty() && spo2->isEmpty() ? PULSE->hide() : PULSE->show();
//pulse->isEmpty() && spo2->isEmpty() ? PULSE->hide() : PULSE->show();
}
if (oxi) {
@ -658,25 +626,20 @@ void Daily::Load(QDate date)
//PULSE->hide();
//SPO2->hide();
}
if (!cpap && !oxi) {
NoData->setText(tr("No data for ")+date.toString(Qt::SystemLocaleLongDate));
NoData->show();
} else
NoData->hide();
if (cpap) {
if (mode==MODE_BIPAP) {
} else if (mode==MODE_APAP) {
html+=("<tr><td colspan=4 align=center><i>")+tr("Time@Pressure")+("</i></td></tr>\n");
TAP->setFixedSize(gwwidth,gwheight);
/* TAP->setFixedSize(gwwidth,gwheight);
QPixmap pixmap=TAP->renderPixmap(gwwidth,gwheight,false);
QByteArray byteArray;
QBuffer buffer(&byteArray); // use buffer to store pixmap into byteArray
buffer.open(QIODevice::WriteOnly);
pixmap.save(&buffer, "PNG");
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n";
html+="<tr><td colspan=4 align=center><img src=\"data:image/png;base64," + byteArray.toBase64() + "\"></td></tr>\n"; */
}
html+="</table><hr height=2><table cellpadding=0 cellspacing=0 border=0 width=100%>";
html+="<tr><td align=center>SessionID</td><td align=center>Date</td><td align=center>Start</td><td align=center>End</td></tr>";
@ -703,7 +666,6 @@ void Daily::Load(QDate date)
if (journal) {
ui->JournalNotes->setHtml(journal->summary[GEN_Notes].toString());
}
RedrawGraphs();
}
void Daily::Unload(QDate date)
@ -853,10 +815,9 @@ void Daily::UpdateCPAPGraphs(Day *day)
//if (!day) return;
if (day) {
day->OpenEvents();
day->OpenWaveforms();
}
for (list<gPointData *>::iterator g=CPAPData.begin();g!=CPAPData.end();g++) {
(*g)->Update(day);
for (list<gLayer *>::iterator g=CPAPData.begin();g!=CPAPData.end();g++) {
(*g)->SetDay(day);
}
};
@ -865,20 +826,16 @@ void Daily::UpdateOXIGraphs(Day *day)
//if (!day) return;
if (day) {
day->OpenEvents();
day->OpenWaveforms();
}
for (list<gPointData *>::iterator g=OXIData.begin();g!=OXIData.end();g++) {
(*g)->Update(day);
for (list<gLayer *>::iterator g=OXIData.begin();g!=OXIData.end();g++) {
(*g)->SetDay(day);
}
}
void Daily::RedrawGraphs()
{
// could recall Min & Max stuff here to reset cache
// instead of using the dodgy notify calls.
for (unsigned i=0;i<Graphs.size();i++) {
Graphs[i]->ResetBounds();
Graphs[i]->updateGL();
}
}
@ -891,8 +848,8 @@ void Daily::on_treeWidget_itemSelectionChanged()
QDateTime d;
if (!item->text(1).isEmpty()) {
d=d.fromString(item->text(1),"yyyy-MM-dd HH:mm:ss");
double st=(d.addSecs(-180)).toMSecsSinceEpoch()/86400000.0;
double et=(d.addSecs(180)).toMSecsSinceEpoch()/86400000.0;
double st=(d.addSecs(-180)).toMSecsSinceEpoch();
double et=(d.addSecs(180)).toMSecsSinceEpoch();
FRW->SetXBounds(st,et);
MP->SetXBounds(st,et);
SF->SetXBounds(st,et);
@ -903,7 +860,6 @@ void Daily::on_treeWidget_itemSelectionChanged()
TV->SetXBounds(st,et);
RR->SetXBounds(st,et);
FLG->SetXBounds(st,et);
}
}

19
daily.h
View File

@ -18,6 +18,7 @@
#include <SleepLib/profiles.h>
#include <Graphs/graphwindow.h>
#include <Graphs/graphdata.h>
#include "Graphs/gLineChart.h"
#include <Graphs/gFlagsLine.h>
namespace Ui {
class Daily;
@ -32,7 +33,7 @@ public:
~Daily();
void ReloadGraphs();
void RedrawGraphs();
QGLWidget *SharedWidget() { return SF; };
QGLWidget *SharedWidget() { return SF; }
private slots:
@ -57,25 +58,25 @@ private:
void UpdateCalendarDay(QDate date);
void UpdateEventsTree(QTreeWidget * tree,Day *day);
gPointData *tap,*tap_eap,*tap_iap,*g_ahi,*frw,*prd,*leak,*pressure_iap,*pressure_eap,*snore;
gPointData *pulse,*spo2,*rr,*mv,*tv,*mp,*flg,*ptb;
//gLineChart *frw,*prd,*leak,*pr_ipap,*pr_epap,*snore,*pulse,*spo2,*rr,*mv,*tv,*mp,*flg,*ptb;
//gPointData *tap,*tap_eap,*tap_iap,*g_ahi,*frw,*prd,*leak,*pressure_iap,*pressure_eap,*snore;
//gPointData *pulse,*spo2,*rr,*mv,*tv,*mp,*flg,*ptb;
gFlagsGroup *fg;
gGraphWindow *PRD,*FRW,*G_AHI,*TAP,*LEAK,*SF,*TAP_EAP,*TAP_IAP,*PULSE,*SPO2,*SNORE,*RR,*MP,*MV,*TV,*FLG,*PTB;
list<gPointData *> OXIData;
list<gPointData *> CPAPData;
list<gLayer *> OXIData;
list<gLayer *> CPAPData;
vector<gGraphWindow *> Graphs;
QGLContext *offscreen_context;
void AddCPAPData(gPointData *d) { CPAPData.push_back(d); }
void AddOXIData(gPointData *d) { OXIData.push_back(d); }
gLayer * AddCPAP(gLayer *d) { CPAPData.push_back(d); return d; }
gLayer * AddOXI(gLayer *d) { OXIData.push_back(d); return d; }
void AddGraph(gGraphWindow *w);
void UpdateCPAPGraphs(Day *day);
void UpdateOXIGraphs(Day *day);
gPointData *flags[11];
Ui::Daily *ui;
Profile *profile;
QDate previous_date;

View File

@ -60,8 +60,8 @@ MainWindow::MainWindow(QWidget *parent) :
//shared_context->create(shared_context);
daily=NULL;
overview=NULL;
oximetry=NULL;
//overview=NULL;
//oximetry=NULL;
qstatusbar=ui->statusbar;
qprogress=new QProgressBar(this);
@ -111,11 +111,11 @@ MainWindow::MainWindow(QWidget *parent) :
daily=new Daily(ui->tabWidget);
ui->tabWidget->insertTab(1,daily,tr("Daily"));
overview=new Overview(ui->tabWidget,daily->SharedWidget());
ui->tabWidget->insertTab(2,overview,tr("Overview"));
//overview=new Overview(ui->tabWidget,daily->SharedWidget());
//ui->tabWidget->insertTab(2,overview,tr("Overview"));
oximetry=new Oximetry(ui->tabWidget,daily->SharedWidget());
ui->tabWidget->insertTab(3,oximetry,tr("Oximetry"));
//oximetry=new Oximetry(ui->tabWidget,daily->SharedWidget());
//ui->tabWidget->insertTab(3,oximetry,tr("Oximetry"));
ui->tabWidget->setCurrentWidget(ui->welcome);
@ -127,14 +127,14 @@ MainWindow::~MainWindow()
daily->close();
delete daily;
}
if (overview) {
/*if (overview) {
overview->close();
delete overview;
}
if (oximetry) {
oximetry->close();
delete oximetry;
}
}*/
DoneGraphs();
Profiles::Done();
mainwin=NULL;
@ -153,11 +153,11 @@ void MainWindow::Startup()
if (daily) daily->ReloadGraphs();
if (overview) {
/*if (overview) {
overview->ReloadGraphs();
overview->UpdateGraphs();
}
}*/
qprogress->hide();
qstatus->setText(tr("Ready"));
@ -189,11 +189,11 @@ void MainWindow::on_action_Import_Data_triggered()
profile->Save();
if (daily) daily->ReloadGraphs();
if (overview) {
/*if (overview) {
overview->ReloadGraphs();
overview->UpdateGraphs();
}
} */
//qDebug() << "overview->ReloadGraphs();";
}
qstatus->setText(tr("Ready"));
@ -253,7 +253,7 @@ void MainWindow::on_dailyButton_clicked()
void MainWindow::on_overviewButton_clicked()
{
ui->tabWidget->setCurrentWidget(overview);
//ui->tabWidget->setCurrentWidget(overview);
}
void MainWindow::on_webView_loadFinished(bool arg1)

View File

@ -16,7 +16,7 @@
const int major_version=0;
const int minor_version=8;
const int revision_number=1;
const int revision_number=2;
namespace Ui {
class MainWindow;
@ -77,8 +77,8 @@ private slots:
private:
Ui::MainWindow *ui;
Daily * daily;
Overview * overview;
Oximetry * oximetry;
//Overview * overview;
//Oximetry * oximetry;
bool first_load;
Profile *profile;
};

View File

@ -18,7 +18,7 @@
#include "Graphs/gFooBar.h"
#include "Graphs/gSessionTime.h"
Overview::Overview(QWidget *parent,QGLWidget * shared) :
/*Overview::Overview(QWidget *parent,QGLWidget * shared) :
QWidget(parent),
ui(new Ui::Overview)
{
@ -269,3 +269,4 @@ void Overview::on_rbDateRange_clicked()
{
UpdateGraphs();
}
*/

View File

@ -7,7 +7,7 @@
#ifndef OVERVIEW_H
#define OVERVIEW_H
#include <QWidget>
/*#include <QWidget>
#include <QGLContext>
#include <QSplitter>
#include <QLabel>
@ -61,5 +61,5 @@ private:
QSplitter *gSplitter;
QLabel *NoData;
};
*/
#endif // OVERVIEW_H

View File

@ -2,7 +2,7 @@
#include <QProgressBar>
#include <QMessageBox>
#include "oximetry.h"
/*#include "oximetry.h"
#include "ui_oximetry.h"
#include "qextserialport/qextserialenumerator.h"
#include "SleepLib/loader_plugins/cms50_loader.h"
@ -374,17 +374,17 @@ void Oximetry::onReadyRead()
if (redraw_spo2)
SPO2->updateGL();
/*if (bytes.size()==3) {
} else if (bytes.size()==2) { // Data bytes in live mode
//if (bytes.size()==3) {
//} else if (bytes.size()==2) { // Data bytes in live mode
// Plethy data
} else {
//} else {
//qDebug() << "Got " << bytes.size() << " bytes";
}*/
/*QString aa=QString::number(bytes.size(),16)+"bytes: ";
for (int i=0;i<bytes.size();i++) {
aa+=" "+QString::number((unsigned char)bytes[i],16);
}
qDebug() << aa; */
//}
//QString aa=QString::number(bytes.size(),16)+"bytes: ";
//for (int i=0;i<bytes.size();i++) {
// aa+=" "+QString::number((unsigned char)bytes[i],16);
//}
//qDebug() << aa;
//lastsize=bytes.size();
}
@ -526,19 +526,19 @@ void Oximetry::on_ImportButton_clicked()
while (rb[startpos]!=0xf0) {
length=(length << 7) | (rb[startpos++] & 0x7f);
}
/*length=(rb[startpos++] & 0x7f) << 14;
length|=(rb[startpos++] & 0x7f) << 7;
length|=(rb[startpos++] & 0x7f);
if (!(rb[startpos]&0x80)) {
length <<= 8;
length|=rb[startpos++];
}*/
/*length=(rb[startpos] ^ 0x80)<< 7 | (rb[startpos+1]);
startpos+=2;
if (!(rb[startpos]&0x80)) {
length|=(rb[startpos]&0x7f) << 14;
startpos++;
} else oneoff=true; */
//length=(rb[startpos++] & 0x7f) << 14;
//length|=(rb[startpos++] & 0x7f) << 7;
//length|=(rb[startpos++] & 0x7f);
//if (!(rb[startpos]&0x80)) {
// length <<= 8;
// length|=rb[startpos++];
//}
//length=(rb[startpos] ^ 0x80)<< 7 | (rb[startpos+1]);
//startpos+=2;
//if (!(rb[startpos]&0x80)) {
// length|=(rb[startpos]&0x7f) << 14;
// startpos++;
//} else oneoff=true;
buffer=new unsigned char [length+32];
//qDebug() << length << startpos;
@ -584,12 +584,12 @@ void Oximetry::on_ImportButton_clicked()
spo2=buffer[i++];
if (pulse!=0 && pulse!=lastpulse) {
data=pulse;
sess->AddEvent(new Event(tt,OXI_Pulse,&data,1));
sess->AddEvent(new Event(tt,OXI_Pulse,0,&data,1));
//qDebug() << "Pulse: " << int(pulse);
}
if (spo2 != 0 && spo2!=lastspo2) {
data=spo2;
sess->AddEvent(new Event(tt,OXI_SPO2,&data,1));
sess->AddEvent(new Event(tt,OXI_SPO2,0,&data,1));
//qDebug() << "SpO2: " << int(spo2);
}
@ -598,9 +598,9 @@ void Oximetry::on_ImportButton_clicked()
tt+=1000;
}
data=pulse;
sess->AddEvent(new Event(tt,OXI_Pulse,&data,1));
sess->AddEvent(new Event(tt,OXI_Pulse,0,&data,1));
data=spo2;
sess->AddEvent(new Event(tt,OXI_SPO2,&data,1));
sess->AddEvent(new Event(tt,OXI_SPO2,0,&data,1));
sess->summary[OXI_PulseMin]=sess->min_event_field(OXI_Pulse,0);
sess->summary[OXI_PulseMax]=sess->max_event_field(OXI_Pulse,0);
sess->summary[OXI_PulseAverage]=sess->weighted_avg_event_field(OXI_Pulse,0);
@ -621,3 +621,4 @@ void Oximetry::on_ImportButton_clicked()
ui->SerialPortsCombo->setEnabled(true);
qstatus->setText("Ready");
}
*/

View File

@ -1,6 +1,6 @@
#ifndef OXIMETRY_H
#define OXIMETRY_H
/*
#include <QWidget>
#include <QGLContext>
@ -61,5 +61,5 @@ private:
int lastpulse, lastspo2;
};
*/
#endif // OXIMETRY_H