Vykreslenie gridu pod sviečkovými grafmi

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.

  • OHLCNokia5110BaseRender
    • OHLCNokia5110LineRender
    • OHLCNokia5110BarRender

Do triedy OHLCNokia5110BaseRender presunieme všetky zhodné funkcie pre vykresľovanie.

  • void drawHeader()
  • void drawFooter()
  • void setDisplay(Adafruit_PCD8544 *d)
  • void drawGrid(ohlcvalue minimum, ohlcvalue maximum, ohlcvalue grid_step)

V odvodených triedach necháme iba samotnú funkciu na vykresľovanie sviečky.

  • void drawBar(int pos, OHLCData<ohlcvalue> *bar)

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.

Program

Hlavný program sa zmodifikuje voči predchádzajúcemu iba mierne. Hlavné úpravy budú v šablónových triedach.

ohlc_nokia_random_grid.ino

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);

  ...
}

candlestick.h

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

Zdrojový kód sa nachádza na GitHub.

Pokračovanie

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


Menu