Zápisník experimentátora
Hierarchy: Sviečkové grafy
V dnešnom dieli si vykreslíme mriežku pod sviečkovým grafom. Mriežka uľahčuje orientáciu v hodnotách, ktoré pri sviečkových grafoch nie sú na displeji. Orientujete sa iba podľa mriežky, ktorá je vykreslená v pravidelných intervaloch.
Opäť použijeme displej Nokia 5110. V minulom dieli sme naprogramovali dve triedy na vykresľovanie pre displej Nokia 5110. Pretože mriežka vyzerá v oboch prípadoch rovnako, je toto dobrá príležitosť na pocvičenie sa v dedení objektov. Navrhneme si nasledovnú hierarchiu tried, ktoré budú rozvíjať predchádzajúci kód.
Do triedy OHLCNokia5110BaseRender presunieme všetky zhodné funkcie pre vykresľovanie.
V odvodených triedach necháme iba samotnú funkciu na vykresľovanie sviečky.
Schéma zapojenia sa v ničom neodlišuje od predchádzajúcich zapojení s displejom Nokia 5110, kde sme nepotrebovali pripojiť žiadne ďalšie súčiastky. Iba Arduino, level shifter a displej Nokia 5110.
Hlavný program sa zmodifikuje voči predchádzajúcemu iba mierne. Hlavné úpravy budú v šablónových triedach.
Tu pribudne iba nastavenie mierky mriežky. V našom prípade chceme mať čiaru každých 10 bodov.
void setup() {
...
// connect renderer to Nokia 5110
ohlc.getRender().setDisplay(&display);
ohlc.setGridStep(10);
...
}
Tu je zmien veľa. Najprv definujeme základnú triedu OHLCNokia5110BaseRender. A v nej funkciu drawGrid, ktorá sa postará o kreslenie mriežky. Kreslenie mriežky je záležitosť matematiky. Delením minimálnej hodnoty grafu požadovaným krokom dostaneme spodnú hranicu mriežky, pretože výsledok zaokrúhlime na celé číslo. A v cykle for pridáme ešte jeden krok, aby sme mriežku dostali aj nad graf. Samotná čiara sa skladá z bodiek, ktoré sú umiestnené každých 5 pixelov, aby vo výsledku mriežka príliš neprekrývala samotný graf.
template<class ohlcvalue>
class OHLCNokia5110BaseRender {
protected:
Adafruit_PCD8544 *display;
public:
OHLCNokia5110BaseRender() : display(NULL) {}
void drawHeader() {}
void drawFooter() {}
void setDisplay(Adafruit_PCD8544 *d) {display=d;}
void drawGrid(ohlcvalue minimum, ohlcvalue maximum, ohlcvalue grid_step) {
const int HEIGHT = 47;
int dv = minimum / grid_step;
ohlcvalue bg = (dv + 0) * grid_step;
for(ohlcvalue i = bg;i<maximum+grid_step;i+=grid_step) {
for(int j=0;j<=84;j+=5)
display->drawPixel(j,HEIGHT-(int)i,BLACK);
}
}
};
Definícia odvodenej triedy sa potom scvrkne na nasledovný kód. Všimnite si, že musíme stále definovať aj parameter šablóny ohlcvalue a musíme ho správne použiť aj pri definícii základnej triedy, od ktorej bude táto trieda odvodená. Kompilátor mal s týmto kódom trochu problém, preto som mu musel pomôcť upresniť, že chcem používať pointer na displej Nokia 5110 a bolo to treba definovať ako this->display.
template<class ohlcvalue>
class OHLCNokia5110BarRender : public OHLCNokia5110BaseRender<ohlcvalue> {
public:
void drawBar(int pos, OHLCData<ohlcvalue> *bar) {
if(this->display==NULL)
return;
int START = 5 + pos * 6;
const int BW = 2;
const int HEIGHT = 47;
int top;
int bottom;
if(bar->o < bar->c) {
top = bar->c;
bottom = bar->o;
} else {
top = bar->o;
bottom = bar->c;
}
// high
this->display->drawLine(START+1*BW,HEIGHT-bar->h,START+1*BW,HEIGHT-top,BLACK);
// low
this->display->drawLine(START+1*BW,HEIGHT-bar->l,START+1*BW,HEIGHT-bottom,BLACK);
// bar
if(bar->o < bar->c) {
this->display->fillRect(START,HEIGHT-bottom,2*BW+1,bottom-top+1,WHITE);
this->display->drawRect(START,HEIGHT-bottom,2*BW+1,bottom-top+1,BLACK);
}
else
this->display->fillRect(START,HEIGHT-bottom,2*BW+1,bottom-top+1,BLACK);
}
};
A na záver už ostal iba upravený kód na vykreslenie grafu aj s mriežkou. Kód vo funkcii draw robí to, že po vykreslení hlavičky spočíta minimum a maximum na sviečkach a požiada renderer, aby s danými parametrami mriežku vykreslil.
template<typename ohlcvalue, const int len, const int stp, typename renderclass>
class OHLCChart {
...
ohlcvalue grid_step;
public:
...
void setGridStep(ohlcvalue value) {
grid_step = value;
}
...
void draw() {
render.drawHeader();
if(grid_step>0 && ohlc_first!=len) {
ohlcvalue minimum = data[ohlc_first].l;
ohlcvalue maximum = data[ohlc_first].h;
for(int i=ohlc_first+1;i<len;i++) {
if(data[i].l<minimum)
minimum = data[i].l;
if(data[i].h>maximum)
maximum = data[i].h;
}
if(minimum!=maximum)
render.drawGrid(minimum,maximum,grid_step);
}
for(int i=ohlc_first;i<len;i++)
render.drawBar(i,data+i);
render.drawFooter();
}
};
Zdrojový kód sa nachádza na GitHub.
Nabudúce budeme konečne zobrazovať reálne namerané údaje o teplote. Upravíme kód tak, aby automaticky prispôsoboval mierku nameraným údajom.
30.08.2016