#include "TimeSeriesCanvas.h" #include "../CommonInterfaces/Common2dCanvasInterface.h" #include "LinearMath/btAlignedObjectArray.h" #include "TimeSeriesFontData.h" #include "LinearMath/btVector3.h" #include struct DataSource { unsigned char m_red; unsigned char m_green; unsigned char m_blue; float m_lastValue; bool m_hasLastValue; DataSource() :m_hasLastValue(false) { } }; struct TimeSeriesInternalData { btAlignedObjectArray m_dataSources; struct Common2dCanvasInterface* m_canvasInterface; int m_canvasIndex; int m_width; int m_height; float m_pixelsPerUnit; float m_zero; int m_timeTicks; int m_ticksPerSecond; float m_yScale; int m_bar; unsigned char m_backgroundRed; unsigned char m_backgroundGreen; unsigned char m_backgroundBlue; unsigned char m_backgroundAlpha; unsigned char m_textColorRed; unsigned char m_textColorGreen; unsigned char m_textColorBlue; unsigned char m_textColorAlpha; float getTime() { return m_timeTicks/(float)m_ticksPerSecond; } TimeSeriesInternalData(int width, int height) :m_width(width), m_height(height), m_pixelsPerUnit(-100), m_zero(height/2.0), m_timeTicks(0), m_ticksPerSecond(100), m_yScale(1), m_bar(0), m_backgroundRed(255), m_backgroundGreen(255), m_backgroundBlue(255), m_backgroundAlpha(255), m_textColorRed(0), m_textColorGreen(0), m_textColorBlue(255), m_textColorAlpha(255) { } }; TimeSeriesCanvas::TimeSeriesCanvas(struct Common2dCanvasInterface* canvasInterface, int width, int height, const char* windowTitle) { m_internalData = new TimeSeriesInternalData(width,height); m_internalData->m_canvasInterface = canvasInterface; if (canvasInterface) { m_internalData->m_canvasIndex = m_internalData->m_canvasInterface->createCanvas(windowTitle,m_internalData->m_width,m_internalData->m_height); } } void TimeSeriesCanvas::addDataSource(const char* dataSourceLabel, unsigned char red,unsigned char green,unsigned char blue) { DataSource dataSource; dataSource.m_red = red; dataSource.m_green = green; dataSource.m_blue = blue; dataSource.m_lastValue = 0; dataSource.m_hasLastValue = false; if (dataSourceLabel) { int numSources = m_internalData->m_dataSources.size(); int row = numSources%3; int column = numSources/3; grapicalPrintf(dataSourceLabel, sTimeSeriesFontData, 50+200*column,m_internalData->m_height-48+row*16, red, green,blue,255); } m_internalData->m_dataSources.push_back(dataSource); } void TimeSeriesCanvas::setupTimeSeries(float yScale, int ticksPerSecond, int startTime, bool clearCanvas) { if (0==m_internalData->m_canvasInterface) return; m_internalData->m_pixelsPerUnit = -(m_internalData->m_height/3.f)/yScale; m_internalData->m_ticksPerSecond = ticksPerSecond; m_internalData->m_yScale = yScale; m_internalData->m_dataSources.clear(); if (clearCanvas) { for (int i=0;im_width;i++) { for (int j=0;jm_height;j++) { m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,i,j, m_internalData->m_backgroundRed, m_internalData->m_backgroundGreen, m_internalData->m_backgroundBlue, m_internalData->m_backgroundAlpha); } } } float zeroPixelCoord = m_internalData->m_zero; float pixelsPerUnit = m_internalData->m_pixelsPerUnit; float yPos = zeroPixelCoord+pixelsPerUnit*yScale; float yNeg = zeroPixelCoord+pixelsPerUnit*-yScale; grapicalPrintf("0", sTimeSeriesFontData, 2,zeroPixelCoord,m_internalData->m_textColorRed,m_internalData->m_textColorGreen,m_internalData->m_textColorBlue,m_internalData->m_textColorAlpha); char label[1024]; sprintf(label,"%2.1f", yScale); grapicalPrintf(label, sTimeSeriesFontData, 2,yPos,m_internalData->m_textColorRed,m_internalData->m_textColorGreen,m_internalData->m_textColorBlue,m_internalData->m_textColorAlpha); sprintf(label,"%2.1f", -yScale); grapicalPrintf(label, sTimeSeriesFontData, 2,yNeg,m_internalData->m_textColorRed,m_internalData->m_textColorGreen,m_internalData->m_textColorBlue,m_internalData->m_textColorAlpha); m_internalData->m_canvasInterface->refreshImageData(m_internalData->m_canvasIndex); } TimeSeriesCanvas::~TimeSeriesCanvas() { if (m_internalData->m_canvasInterface && m_internalData->m_canvasIndex>=0) { m_internalData->m_canvasInterface->destroyCanvas(m_internalData->m_canvasIndex); } delete m_internalData; } float TimeSeriesCanvas::getCurrentTime() const { return m_internalData->getTime(); } void TimeSeriesCanvas::grapicalPrintf(const char* str, void* fontData, int rasterposx,int rasterposy, unsigned char red, unsigned char green, unsigned char blue, unsigned char alpha) { unsigned char c; int x=0; int xx=0; while ((c = (unsigned char) *str++)) { x=xx; unsigned char* fontPtr = (unsigned char*) fontData; char ch = c-32; int sx=ch%16; int sy=ch/16; for (int i=sx*16;i<(sx*16+16);i++) { int y=0; for (int j=sy*16;j<(sy*16+16);j++) { unsigned char packedColor = (fontPtr[i*3+255*256*3-(256*j)*3]); //float colorf = packedColor ? 0.f : 1.f; float colorf = packedColor/255.f;// ? 0.f : 1.f; btVector4 rgba(colorf,colorf,colorf,1.f); if (colorf) { if ((rasterposx+x>=0) && (rasterposx+x < m_internalData->m_width) && (rasterposy+y>=0) && (rasterposy+ym_height)) { m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,rasterposx+x,rasterposy+y, red,green,blue,alpha); } } y++; } x++; } xx+=10; } } void TimeSeriesCanvas::shift1PixelToLeft() { int resetVal = 10; int countdown = resetVal; //shift pixture one pixel to the left for (int j=50;jm_height-48;j++) { for (int i=40;im_internalData->m_width;i++) { unsigned char red, green, blue, alpha; m_internalData->m_canvasInterface->getPixel(m_internalData->m_canvasIndex,i,j,red,green,blue,alpha); m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,i-1,j,red,green,blue,alpha); } if (!m_internalData->m_bar) { if (!countdown--) { countdown=resetVal; m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,j,0,0,0,255); } else { m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,j,255,255,255,255); } } else { m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,j,255,255,255,255); } } { int resetVal = 2; static int countdown = resetVal; if (!countdown--) { countdown=resetVal; m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,m_internalData->m_zero,0,0,0,255); } } { int resetVal = 10; static int countdown = resetVal; if (!countdown--) { countdown=resetVal; float zeroPixelCoord = m_internalData->m_zero; float pixelsPerUnit = m_internalData->m_pixelsPerUnit; float yPos = zeroPixelCoord+pixelsPerUnit*m_internalData->m_yScale; float yNeg = zeroPixelCoord+pixelsPerUnit*-m_internalData->m_yScale; m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1, yPos,0,0,0,255); m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1, yNeg,0,0,0,255); } } if (!m_internalData->m_bar) { char buf[1024]; float time = m_internalData->getTime(); sprintf(buf,"%2.0f",time); grapicalPrintf(buf, sTimeSeriesFontData, m_internalData->m_width-25,m_internalData->m_zero+3,0,0,0,255); m_internalData->m_bar=m_internalData->m_ticksPerSecond; } m_internalData->m_timeTicks++; m_internalData->m_bar--; } void TimeSeriesCanvas::insertDataAtCurrentTime(float orgV, int dataSourceIndex, bool connectToPrevious) { if (0==m_internalData->m_canvasInterface) return; btAssert(dataSourceIndex < m_internalData->m_dataSources.size()); float zero = m_internalData->m_zero; float amp = m_internalData->m_pixelsPerUnit; //insert some new value(s) in the right-most column { // float time = m_internalData->getTime(); float v = zero+amp*orgV; m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,v, m_internalData->m_dataSources[dataSourceIndex].m_red, m_internalData->m_dataSources[dataSourceIndex].m_green, m_internalData->m_dataSources[dataSourceIndex].m_blue, 255 ); if (connectToPrevious && m_internalData->m_dataSources[dataSourceIndex].m_hasLastValue) { for (int value=m_internalData->m_dataSources[dataSourceIndex].m_lastValue;value<=v;value++) { if (value>=0 && value < float(m_internalData->m_height-1)) { m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,value, m_internalData->m_dataSources[dataSourceIndex].m_red, m_internalData->m_dataSources[dataSourceIndex].m_green, m_internalData->m_dataSources[dataSourceIndex].m_blue, 255 ); } } for (int value=v;value<=m_internalData->m_dataSources[dataSourceIndex].m_lastValue;value++) { if (value>=0 && value < float(m_internalData->m_height-1)) { m_internalData->m_canvasInterface->setPixel(m_internalData->m_canvasIndex,m_internalData->m_width-1,value, m_internalData->m_dataSources[dataSourceIndex].m_red, m_internalData->m_dataSources[dataSourceIndex].m_green, m_internalData->m_dataSources[dataSourceIndex].m_blue, 255); } } } m_internalData->m_dataSources[dataSourceIndex].m_lastValue = v; m_internalData->m_dataSources[dataSourceIndex].m_hasLastValue = true; } } void TimeSeriesCanvas::nextTick() { shift1PixelToLeft(); m_internalData->m_canvasInterface->refreshImageData(m_internalData->m_canvasIndex); }