/* gXAxis Implementation Copyright (c)2011 Mark Watkins <jedimark@users.sourceforge.net> License: GPL */ #include <math.h> #include <QDebug> #include "gXAxis.h" const int divisors[]={86400000,2880000,14400000,7200000,3600000,2700000,1800000,1200000,900000,600000,300000,120000,60000,45000,30000,20000,15000,10000,5000,2000,1000,100,50,10}; const int divcnt=sizeof(divisors)/sizeof(int); gXAxis::gXAxis(QColor col) :Layer(EmptyChannel) { m_line_color=col; m_text_color=col; m_major_color=Qt::darkGray; m_minor_color=Qt::lightGray; m_show_major_lines=false; m_show_minor_lines=false; m_show_minor_ticks=true; m_show_major_ticks=true; QDateTime d=QDateTime::currentDateTime(); QTime t1=d.time(); QTime t2=d.toUTC().time(); tz_offset=t2.secsTo(t1)/60L; tz_offset*=60000L; } gXAxis::~gXAxis() { } void gXAxis::paint(gGraph & w,int left,int top, int width, int height) { double px,py; int start_px=left; int start_py=top; //int width=scrx-(w.GetLeftMargin()+w.GetRightMargin()); // float height=scry-(w.GetTopMargin()+w.GetBottomMargin()); if (width<40) return; qint64 minx; qint64 maxx; if (w.blockZoom()) { minx=w.rmin_x; maxx=w.rmax_x; } else { minx=w.min_x; maxx=w.max_x; } qint64 xx=maxx-minx; if (xx<=0) return; //Most of this could be precalculated when min/max is set.. QString fd,tmpstr; int divmax,dividx; int fitmode; if (xx>86400000L) { // Day fd="MMM 00:00"; dividx=0; divmax=10; fitmode=0; } else if (xx>600000) { // Minutes fd="00:00"; dividx=0; divmax=18; fitmode=1; } else if (xx>5000) { // Seconds fd="00:00:00"; dividx=9; divmax=20; fitmode=2; } else { // Microseconds fd="00:00:00:000"; dividx=19; divmax=divcnt; fitmode=3; } float x,y; GetTextExtent(fd,x,y); if (x<=0) { qWarning() << "gXAxis::Plot() x<=0 font size bug"; return; } int max_ticks=width/(x+15); // Max number of ticks that will fit int fit_ticks=0; int div=-1; qint64 closest=0,tmp,tmpft; for (int i=dividx;i<divmax;i++){ tmpft=xx/divisors[i]; tmp=max_ticks-tmpft; if (tmp<0) continue; if (tmpft>closest) { // Find the closest scale to the number closest=tmpft; // that will fit div=i; fit_ticks=tmpft; } } if (fit_ticks==0) { qDebug() << "gXAxis::Plot() Couldn't fit ticks.. Too short?" << minx << maxx << xx; return; } if ((div<0) || (div>divcnt)) { qDebug() << "gXAxis::Plot() div out of bounds"; return; } qint64 step=divisors[div]; //Align left minimum to divisor by losing precision qint64 aligned_start=minx/step; aligned_start*=step; qint32 vertcnt=0; GLshort * vertarray=vertex_array[0]; if (vertarray==NULL) { qWarning() << "VertArray==NULL"; return; } while (aligned_start<minx) { aligned_start+=step; } double xmult=double(width)/double(xx); double step_pixels=double(step/10.0)*xmult; py=left+double(aligned_start-minx)*xmult; for (int i=0;i<10;i++) { py-=step_pixels; if (py<start_px) continue; vertarray[vertcnt++]=py; vertarray[vertcnt++]=top; vertarray[vertcnt++]=py; vertarray[vertcnt++]=top+4; } w.qglColor(Qt::black); for (qint64 i=aligned_start;i<maxx;i+=step) { px=double(i-minx)*xmult; px+=left; vertarray[vertcnt++]=px; vertarray[vertcnt++]=top; vertarray[vertcnt++]=px; vertarray[vertcnt++]=top+6; qint64 j=i+tz_offset; int ms=j % 1000; int m=(j/60000L) % 60L; int h=(j/3600000L) % 24L; int s=(j/1000L) % 60L; if (fitmode==0) { static QString dow[]={"Sun","Mon","Tue","Wed","Thu","Fri","Sat"}; int d=(j/86400000) % 7; tmpstr=QString("%1 %2:%3").arg(dow[d]).arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')); } else if (fitmode==1) { // minute tmpstr=QString("%1:%2").arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')); } else if (fitmode==2) { // second tmpstr=QString("%1:%2:%3").arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')).arg(s,2,10,QChar('0')); } else if (fitmode==3) { // milli tmpstr=QString("%1:%2:%3:%4").arg(h,2,10,QChar('0')).arg(m,2,10,QChar('0')).arg(s,2,10,QChar('0')).arg(ms,3,10,QChar('0')); } //w.renderText(px-(x/2),scry-(w.GetBottomMargin()-18),tmpstr); //DrawText(w,tmpstr,,0); w.renderText(tmpstr,px-(x/2),top+18); py=px; for (int j=1;j<10;j++) { py+=step_pixels; if (py>=left+width) break; vertarray[vertcnt++]=py; vertarray[vertcnt++]=top; vertarray[vertcnt++]=py; vertarray[vertcnt++]=top+4; if (vertcnt>=maxverts) { break; } } if (vertcnt>=maxverts) { qWarning() << "maxverts exceeded in gXAxis::Plot()"; break; } } glEnableClientState(GL_VERTEX_ARRAY); glLineWidth(1); w.qglColor(Qt::black); glVertexPointer(2, GL_SHORT, 0, vertarray); glDrawArrays(GL_LINES, 0, vertcnt>>1); glDisableClientState(GL_VERTEX_ARRAY); // deactivate vertex arrays after drawing // glDisable(GL_SCISSOR_TEST); }