Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

初期化時に全部かけるように関数に切り出す #69

Open
github-actions bot opened this issue Jun 20, 2020 · 0 comments
Open

初期化時に全部かけるように関数に切り出す #69

github-actions bot opened this issue Jun 20, 2020 · 0 comments
Labels

Comments

@github-actions
Copy link

初期化時に全部かけるように関数に切り出す

軸の点線

// TODO: 初期化時に全部かけるように関数に切り出す

#include <cstdint>
#include <algorithm>

#include <LovyanGFX.h>

#include "DrawDefs.h"

/**
 * @brief X軸の描画設定
 */
enum class ChartMode : uint32_t {
    Overwrite, /**< 最初の位置に戻って最初のデータの上に上書き */
    Scroll, /**< 全体的に左にシフトしてから新しいデータを表示する */
    Infinite, /**< 過去のデータを圧縮して新しいデータが常に表示されるようにする */
};

/**
 * @brief  Y軸の設定
 */
struct AxisY {
    float min; /**< 最小値 */
    float max; /**< 最大値 */
};

/**
 * @brief Chartの描画設定
 */
struct ChartConfig {
    ChartMode mode; /**< 描画設定 */
    Rect  rect; /**< 表示位置とサイズ */
    AxisY axisY0; /**< 左側のY軸設定 */
    AxisY axisY1; /**< 左側のY軸設定 */
    Color axisColor; /**< 軸の色 */
    uint32_t axisTickness; /**< 軸の太さ */
    Color backColor; /**< 背景色 */
};

/**
 * @brief Chartの点追加時の描画設定です
 * @note Chart classで任意数のデータ系列を扱うため、内部で保持せず外部で指定する方式にしています
 */
struct PlotConfig {
    uint32_t axisYIndex; /**< Y軸のIndex、左なら0、右なら1を指定(それ以上に軸を増やす実装は未対応) */
    Color color; /**< 色 */
};

/**
 * @brief LovyanGFXを使ってチャートを描画する機能を提供します。
 * @note このクラスは描画を行うのみで履歴値は保持しません。点数を大きくしてもリソースを圧迫しません
 */
class Chart {
    public:
        /**
         * @brief Construct a new Chart object
         */
        Chart(void) {}

        /**
         * @brief Destroy the Chart object
         */
        virtual ~Chart(void) {}

        /**
         * @brief グラフ描画設定を初期化します
         * 
         * @param config 描画設定
         * @param drawDst 描画先lcd or offscreen bufferを指定します
        *
         * @retval true 描画完了
         * @retval false 描画失敗
         */
        bool init(LovyanGFX& drawDst, const ChartConfig& config) {
            // release buffer
            if (this->isInitialized) {
                this->isInitialized = false;
            }
            // config validation
            if (config.rect.width == 0) return false;
            if (config.rect.height == 0) return false;

            // set variables
            this->config = config;
            this->xIndex = 0;

            // 背景準備
            this->drawBackground(drawDst);
            this->drawAxis(drawDst);

            // 設定完了
            this->isInitialized = true;
            return true;
        }

        /**
         * @brief 点を追加します
         * @remark 一通りの系列データをplotし終わったらflush()を呼び出してX軸位置をincrementしてください
         * 
         * @param y 最新値
         * @param plotConfig 描画設定
         * @param drawDst 描画先lcd or offscreen bufferを指定します
         */
        void plot(LovyanGFX& drawDst, float y, const PlotConfig& plotConfig) {
            // 未初期化なら失敗
            if (!this->isInitialized) {
                return;
            }
            // TODO: Infinite/Scroll対応

            // 描画位置計算
            const float minY   = (plotConfig.axisYIndex == 0) ? this->config.axisY0.min : this->config.axisY1.min;
            const float maxY   = (plotConfig.axisYIndex == 0) ? this->config.axisY0.max : this->config.axisY1.max;
            const float areaY  = (maxY - minY);
            if (areaY == 0.0f) return;
            const float ratioY = (y - minY) / areaY;
            if (ratioY < 0.0f || 1.0f < ratioY) return;
            // ratioYに0.0f~1.0fが入っているので描画領域からY座標を推定
            const uint32_t plotY = (this->getPlotOffsetY0() + this->getPlotHeight()) - static_cast<uint32_t>(ratioY * this->getPlotHeight());

            // 点を打つ
            const auto plotColor =
                drawDst.color888(
                    plotConfig.color.r, 
                    plotConfig.color.g, 
                    plotConfig.color.b
                    );
            const uint32_t plotX = this->getPlotOffsetX0() + this->xIndex;
            drawDst.drawPixel(plotX, plotY, plotColor);

        }

        /**
         * @brief Xのデータ位置を進め、plot内容を確定させます
         * 
         * @param drawDst 描画先lcd or offscreen bufferを指定します
         */
        void next(LovyanGFX& drawDst) {
            // 未初期化なら失敗
            if (!this->isInitialized) {
                return;
            }
            // x indexをすすめる
            switch (this->config.mode) {
                case ChartMode::Overwrite:
                    // 全部描画したら最初に戻る
                    this->xIndex = (this->xIndex + 1) % this->getPlotWidth();
                    break;
                case ChartMode::Scroll:
                case ChartMode::Infinite:
                    // いずれも一番最後の領域に描く
                    // 差分は0~n-1のSpriteをシフトするか圧縮するかの差
                    this->xIndex = std::min(this->xIndex + 1, this->getPlotWidth() - 1);
                    break;
                default:
                    // 未実装
                    break;
            }
            // 予め塗りつぶしておく
            const auto backColor =
                drawDst.color888(
                    this->config.backColor.r, 
                    this->config.backColor.g, 
                    this->config.backColor.b
                    );

            // 描画領域初期化
            drawDst.fillRect(
                this->getPlotOffsetX0() + this->xIndex,
                this->getPlotOffsetY0(),
                1,
                this->getPlotHeight(),
                backColor
                );

            // TODO: 初期化時に全部かけるように関数に切り出す
            // 軸の点線
            if (this->xIndex % 20 == 0) { // TODO: configへ
                const PlotConfig y0Config = {
                    .axisYIndex = 0,
                    .color = {
                        .r = this->config.axisColor.r, 
                        .g = this->config.axisColor.g, 
                        .b = this->config.axisColor.b
                    },
                };
                const PlotConfig y1Config = {
                    .axisYIndex = 1,
                    .color = {
                        .r = this->config.axisColor.r, 
                        .g = this->config.axisColor.g, 
                        .b = this->config.axisColor.b
                    },
                };

                const uint32_t n = 5; // TODO: configへ
                for (uint32_t i = 0; i < n; i ++) {  
                    const float ratio = static_cast<float>(i) / static_cast<float>(n);
                    const float y0 =  ratio * (this->config.axisY0.max - this->config.axisY0.min) + this->config.axisY0.min;
                    const float y1 =  ratio * (this->config.axisY1.max - this->config.axisY1.min) + this->config.axisY1.min;
                    this->plot(drawDst, y0, y0Config);
                    this->plot(drawDst, y1, y1Config);
                }
            }
        }

    protected:
        // local variables
        bool isInitialized; /**< initが呼ばれていなければfalse */
        ChartConfig config; /**< 描画設定 */
        uint32_t xIndex; /**< X軸のデータ位置 */

        /**
         * @brief 背景を塗りつぶします
         * 
         * @param drawDst 描画先
         */
        void drawBackground(LovyanGFX& drawDst) {
            // 背景塗りつぶし用
            const auto backColor =
                drawDst.color888(
                    this->config.backColor.r, 
                    this->config.backColor.g, 
                    this->config.backColor.b
                    );

            // 描画領域初期化
            drawDst.fillRect(
                this->config.rect.x,
                this->config.rect.y,
                this->config.rect.width,
                this->config.rect.height,
                backColor
                );
        }
        /**
         * @brief 軸を描画します
         * 
         * @param drawDst 描画先
         */
        void drawAxis(LovyanGFX& drawDst) {
            const auto axisColor = 
                drawDst.color888(
                    this->config.axisColor.r, 
                    this->config.axisColor.g, 
                    this->config.axisColor.b
                    );
            for (uint32_t t = 0; t < this->config.axisTickness; t++) {
                // top
                drawDst.drawLine(
                    this->config.rect.x,
                    this->config.rect.y + t,
                    this->config.rect.x + this->config.rect.width,
                    this->config.rect.y + t,
                    axisColor
                    );
                // bottom
                drawDst.drawLine(
                    this->config.rect.x,
                    this->config.rect.y + this->config.rect.height - t,
                    this->config.rect.x + this->config.rect.width,
                    this->config.rect.y + this->config.rect.height - t,
                    axisColor
                    );
                // left
                drawDst.drawLine(
                    this->config.rect.x + t,
                    this->config.rect.y,
                    this->config.rect.x + t,
                    this->config.rect.y + this->config.rect.height,
                    axisColor
                    );
                // right
                drawDst.drawLine(
                    this->config.rect.x + this->config.rect.width - t,
                    this->config.rect.y,
                    this->config.rect.x + this->config.rect.width - t,
                    this->config.rect.y + this->config.rect.height,
                    axisColor
                    );
            }
        }
        /**
         * @brief 描画領域の横幅を取得します
         * 
         * @return constexpr uint32_t 
         */
        constexpr uint32_t getPlotWidth(void) {
            return this->config.rect.width - this->config.axisTickness * 2;
        }

        /**
         * @brief 描画領域の高さを取得します
         * 
         * @return constexpr uint32_t 
         */
        constexpr uint32_t getPlotHeight(void) {
            return this->config.rect.height - this->config.axisTickness * 2;
        }

        /**
         * @brief グラフ描画位置の左上を取得します
         * 
         * @return constexpr uint32_t 
         */
        constexpr uint32_t getPlotOffsetX0(void) {
            return this->config.rect.x + this->config.axisTickness;
        }

        /**
         * @brief グラフ描画位置の左上を取得します
         * 
         * @return constexpr uint32_t 
         */
        constexpr uint32_t getPlotOffsetY0(void) {
            return this->config.rect.y + this->config.axisTickness;
        }


};

#endif /* CHART_H */
 No newline at end of file
ew file mode 100644
ndex 0000000..19fdadc
++ b/src/ui/control/DrawDefs.h

e6638a02e8e6528c84ebf59ad7fcf777e5e3cd46

@github-actions github-actions bot added the todo label Jun 20, 2020
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

0 participants