summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorYuval Adam <_@yuv.al>2021-12-18 11:45:26 +0200
committerYuval Adam <_@yuv.al>2021-12-18 11:45:26 +0200
commitc1331d40912bc808f927c2f742da44530039123e (patch)
treed4dbecd20686dd764569a7a900b4984c8e0e8346
parent74b082c851303ff0a87b492c5f3c40759d1fd40c (diff)
Add lots of graphics libs and show axl readings
-rw-r--r--HelloWorld/ADXL335.cpp84
-rw-r--r--HelloWorld/ADXL335.h84
-rw-r--r--HelloWorld/HelloWorld.ino48
-rw-r--r--HelloWorld/seeed_graphics_base.cpp155
-rw-r--r--HelloWorld/seeed_graphics_base.h418
-rw-r--r--HelloWorld/seeed_graphics_define.h102
-rw-r--r--HelloWorld/seeed_line_chart.h422
7 files changed, 1312 insertions, 1 deletions
diff --git a/HelloWorld/ADXL335.cpp b/HelloWorld/ADXL335.cpp
new file mode 100644
index 0000000..9abdb3f
--- /dev/null
+++ b/HelloWorld/ADXL335.cpp
@@ -0,0 +1,84 @@
+/*
+ ADXL335.h
+ Library for accelerometer_ADXL335
+
+ Copyright (c) 2013 seeed technology inc.
+ Author : FrankieChu
+ Create Time : Jan 2013
+ Change Log :
+
+ The MIT License (MIT)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#include <Arduino.h>
+#include "ADXL335.h"
+
+void ADXL335::pinsInit() {
+ pinMode(X_AXIS_PIN, INPUT);
+ pinMode(Y_AXIS_PIN, INPUT);
+ pinMode(Z_AXIS_PIN, INPUT);
+}
+void ADXL335::begin() {
+ pinsInit();
+ scale = (float)SENSITIVITY * ADC_AMPLITUDE / ADC_REF;
+}
+void ADXL335::getXYZ(int* x, int* y, int* z) {
+ *x = analogRead(X_AXIS_PIN);
+ *y = analogRead(Y_AXIS_PIN);
+ *z = analogRead(Z_AXIS_PIN);
+}
+void ADXL335::getAcceleration(float* ax, float* ay, float* az) {
+ int x, y, z;
+ float xvoltage, yvoltage, zvoltage;
+ getXYZ(&x, &y, &z);
+
+ xvoltage = (float)x * ADC_REF / ADC_AMPLITUDE;
+ yvoltage = (float)y * ADC_REF / ADC_AMPLITUDE;
+ zvoltage = (float)z * ADC_REF / ADC_AMPLITUDE;
+
+ *ax = (xvoltage - ZERO_X) / SENSITIVITY;
+ *ay = (yvoltage - ZERO_Y) / SENSITIVITY;
+ *az = (zvoltage - ZERO_Z) / SENSITIVITY;
+}
+float ADXL335::getAccelerationX() {
+ int x, y, z;
+ float xvoltage, ax;
+ getXYZ(&x, &y, &z);
+ xvoltage = (float)x * ADC_REF / ADC_AMPLITUDE;
+ ax = (xvoltage - ZERO_X) / SENSITIVITY;
+ return ax;
+}
+float ADXL335::getAccelerationY() {
+ int x, y, z;
+ float yvoltage, ay;
+ getXYZ(&x, &y, &z);
+ yvoltage = (float)y * ADC_REF / ADC_AMPLITUDE;
+ ay = (yvoltage - ZERO_Y) / SENSITIVITY;
+ return ay;
+}
+float ADXL335::getAccelerationZ() {
+ int x, y, z;
+ float zvoltage, az;
+ getXYZ(&x, &y, &z);
+ zvoltage = (float)z * ADC_REF / ADC_AMPLITUDE;
+ az = (zvoltage - ZERO_Z) / SENSITIVITY;
+ return az;
+}
diff --git a/HelloWorld/ADXL335.h b/HelloWorld/ADXL335.h
new file mode 100644
index 0000000..cc70a03
--- /dev/null
+++ b/HelloWorld/ADXL335.h
@@ -0,0 +1,84 @@
+/*
+ ADXL335.h
+ Library for accelerometer_ADXL335
+
+ Copyright (c) 2013 seeed technology inc.
+ Author : FrankieChu
+ Create Time : Jan 2013
+ Change Log :
+
+ The MIT License (MIT)
+
+ Permission is hereby granted, free of charge, to any person obtaining a copy
+ of this software and associated documentation files (the "Software"), to deal
+ in the Software without restriction, including without limitation the rights
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
+ copies of the Software, and to permit persons to whom the Software is
+ furnished to do so, subject to the following conditions:
+
+ The above copyright notice and this permission notice shall be included in
+ all copies or substantial portions of the Software.
+
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
+ THE SOFTWARE.
+*/
+
+#ifndef __ADXL335_H__
+#define __ADXL335_H__
+
+#include <Arduino.h>
+
+// macro definitions of Analog read pins
+#ifndef X_AXIS_PIN
+#define X_AXIS_PIN A0
+#endif
+#ifndef Y_AXIS_PIN
+#define Y_AXIS_PIN A1
+#endif
+#ifndef Z_AXIS_PIN
+#define Z_AXIS_PIN A2
+#endif
+
+// amplitude of the 10bit-ADC of Arduino is 1024LSB, using as default
+#ifndef ADC_AMPLITUDE
+#define ADC_AMPLITUDE 1024
+#endif
+#ifndef ADC_REF
+#define ADC_REF 5 // ADC reference is 5v
+#endif
+
+// accleration of X-AXIS is 0g, the voltage of X-AXIS is 1.22v
+#ifndef ZERO_X
+#define ZERO_X 1.22
+#endif
+#ifndef ZERO_Y
+#define ZERO_Y 1.22 //
+#endif
+#ifndef ZERO_Z
+#define ZERO_Z 1.25 //
+#endif
+
+// sensitivity of X/Y/Z axis is 0.25v/g
+#ifndef SENSITIVITY
+#define SENSITIVITY 0.25
+#endif
+
+class ADXL335 {
+ private:
+ void pinsInit();
+ float scale;
+ public:
+ void begin();
+ void getXYZ(int* x, int* y, int* z);
+ void getAcceleration(float* ax, float* ay, float* az);
+ float getAccelerationX();
+ float getAccelerationY();
+ float getAccelerationZ();
+};
+
+#endif
diff --git a/HelloWorld/HelloWorld.ino b/HelloWorld/HelloWorld.ino
index ad56df4..defcab1 100644
--- a/HelloWorld/HelloWorld.ino
+++ b/HelloWorld/HelloWorld.ino
@@ -1,6 +1,16 @@
-#include"TFT_eSPI.h"
+#include "TFT_eSPI.h"
+#include "ADXL335.h"
+#include "seeed_graphics_define.h"
+#include "seeed_graphics_base.h"
+#include "seeed_line_chart.h"
TFT_eSPI tft;
+ADXL335 axl;
+
+#define max_size 50
+
+doubles accelerator_readings[3];
+TFT_eSprite spr = TFT_eSprite(&tft);
void setup() {
tft.begin();
@@ -10,8 +20,44 @@ void setup() {
tft.setTextSize(4);
tft.drawString("Hello world!", 20, 100);
+ spr.createSprite(TFT_HEIGHT, TFT_WIDTH);
+
+ axl.begin();
}
void loop() {
+ spr.fillSprite(TFT_WHITE);
+ float ax = axl.getAccelerationX();
+ float ay = axl.getAccelerationY();
+ float az = axl.getAccelerationZ();
+
+ if (accelerator_readings[0].size() == max_size) {
+ for (uint8_t i = 0; i<3; i++){
+ accelerator_readings[i].pop();
+ }
+ }
+ accelerator_readings[0].push(ax);
+ accelerator_readings[1].push(ay);
+ accelerator_readings[2].push(az);
+
+ auto header = text(0, 0);
+ header.value("Acceleration Readings");
+ header.align(center);
+ header.valign(vcenter);
+ header.width(tft.width());
+ header.thickness(2);
+ header.height(header.font_height() * 2);
+ header.draw();
+
+ auto content = line_chart(20, header.height());
+ content.height(tft.height() - header.height() * 1.5);
+ content.width(tft.width() - content.x() * 2);
+ content.based_on(-2.0);
+ content.show_circle(false);
+ content.value({accelerator_readings[0],accelerator_readings[1], accelerator_readings[2]});
+ content.color(TFT_BLUE, TFT_RED, TFT_GREEN);
+ content.draw();
+ spr.pushSprite(0, 0);
+ delay(50);
}
diff --git a/HelloWorld/seeed_graphics_base.cpp b/HelloWorld/seeed_graphics_base.cpp
new file mode 100644
index 0000000..012687b
--- /dev/null
+++ b/HelloWorld/seeed_graphics_base.cpp
@@ -0,0 +1,155 @@
+#include<math.h>
+#include"seeed_graphics_base.h"
+
+std::vector<color_t> classic_colors {
+ yellow,
+ red,
+ green,
+ black,
+ blue,
+ darkcyan,
+ magenta,
+};
+
+constexpr double pi = 3.14159265358979323846;
+extern TFT_eSprite spr;
+
+namespace detail {
+ void draw(void * poly, bool gen){
+ detail::poly<polygen> & p = *(detail::poly<polygen> *)poly;
+ auto default_color = black;
+ auto default_thickness = pan_thickness;
+ auto & value = p.value();
+ auto & color = p.color();
+ auto & thickness = p.thickness();
+
+ if (value.size() <= 1) {
+ return;
+ }
+ for (size_t i = 1; i < value.size() + gen; i++){
+ auto ai = (i - 1) % value.size();
+ auto bi = (i) % value.size();
+ auto a = value[ai];
+ auto b = value[bi];
+ if (i - 1 < color.size()){
+ default_color = color[i - 1];
+ }
+ if (i - 1 < thickness.size()){
+ default_thickness = thickness[i - 1];
+ }
+ line(a, b)
+ .color(default_color)
+ .thickness(default_thickness)
+ .draw();
+ }
+ }
+}
+
+void dot::draw() {
+ spr.drawPixel(_x, _y, _color);
+}
+void line::draw() {
+ spr.drawLine(_x0, _y0, _x1, _y1, _color);
+}
+void dash_line::draw() {
+ point origin(_x, _y);
+ point solid_offset;
+ point empty_offset;
+ point end;
+ if (_orientation == horizon) {
+ solid_offset = point(_solid, 0);
+ empty_offset = point(_empty, 0);
+ end = origin(_length - 1, 0);
+ }
+ else {
+ solid_offset = point(0, _solid);
+ empty_offset = point(0, _empty);
+ end = origin(0, _length - 1);
+ }
+ for (bool loop = true; loop;) {
+ auto next = origin(solid_offset);
+ if (next.x > end.x) {
+ next.x = end.x;
+ loop = false;
+ }
+ if (next.y > end.y) {
+ next.y = end.y;
+ loop = false;
+ }
+ line(origin, next)
+ .color(_color)
+ .thickness(_thickness)
+ .draw();
+ origin = next(empty_offset);
+ }
+}
+
+void rectangle::draw() {
+ auto origin = adjust(_width, _height);
+ auto left_top = origin;
+ auto left_bottom = origin(0, -(pos_t)_height + 1);
+ auto right_top = left_top(_width - 1, 0);
+ auto right_bottom = left_bottom(_width - 1, 0);
+ spr.drawRect(left_top.x, left_top.y, _width, _height, _color);
+
+ if (_fill != transparent) {
+ spr.fillRect(left_top.x + 1, left_top.y + 1, _width - 2, _height - 2, _fill);
+ }
+}
+
+void ellipse::draw() {
+ auto p = adjust(_width, _height);
+ if (_fill != transparent) {
+ spr.fillEllipse(_x, _y, _width / 2, _height / 2, _fill);
+ }
+ spr.drawEllipse(_x, _y, _width / 2, _height / 2, _color);
+}
+text & text::font(font_t value){
+ _font = value;
+ spr.setTextFont(uint8_t(value));
+ return this[0];
+}
+text & text::thickness(pix_t value){
+ _thickness = value;
+ spr.setTextSize(uint8_t(value));
+ return this[0];
+}
+text & text::font_height(pix_t * value) {
+ font(font());
+ thickness(thickness());
+ value[0] = spr.fontHeight();
+ return this[0];
+}
+text & text::content_width(pix_t * value) {
+ font(font());
+ thickness(thickness());
+ value[0] = spr.textWidth(_value);
+ return this[0];
+}
+
+void text::draw(){
+ pix_t height = font_height();
+ pix_t width = content_width();
+ point p = adjust(width, height);
+ if (_align == center){
+ p.x += (_width - width) / 2;
+ }
+ else if (_align == right){
+ p.x += _width - width;
+ }
+ if (_valign == vcenter){
+ p.y += (_height - height) / 2;
+ }
+ else if (_valign == bottom){
+ p.y += _height - height;
+ }
+ spr.setTextColor(_color);
+ spr.drawString(_value, p.x, p.y);
+}
+void polyline::draw() {
+ detail::draw(this, false);
+}
+void polygen::draw() {
+ detail::draw(this, true);
+}
+
diff --git a/HelloWorld/seeed_graphics_base.h b/HelloWorld/seeed_graphics_base.h
new file mode 100644
index 0000000..994f1e2
--- /dev/null
+++ b/HelloWorld/seeed_graphics_base.h
@@ -0,0 +1,418 @@
+#pragma once
+#include"seeed_graphics_define.h"
+
+#define xlist(...) __VA_ARGS__
+#define xprop(type,name,...) \
+protected: \
+type _ ## name; \
+public: \
+auto & name(type value) { \
+ _ ## name = value; \
+ return (__VA_ARGS__ this)[0]; \
+} \
+auto & name(type * value){ \
+ value[0] = _ ## name; \
+ return (__VA_ARGS__ this)[0]; \
+} \
+auto & name(){ \
+ return _ ## name; \
+}
+
+#define xvprop(type,name,...) \
+protected: \
+std::vector<type> _ ## name; \
+public: \
+auto & name(type value) { \
+ _ ## name = std::vector<type>{ value }; \
+ return (__VA_ARGS__ this)[0]; \
+} \
+template<class ... arg> \
+auto & name(type value, arg ... list) { \
+ _ ## name = std::vector<type>{ value, list... }; \
+ return (__VA_ARGS__ this)[0]; \
+} \
+auto & name(std::vector<type> * value){ \
+ value[0] = _ ## name; \
+ return (__VA_ARGS__ this)[0]; \
+} \
+auto & name(){ \
+ return _ ## name; \
+}
+
+
+#define xpoint(type,...) \
+xprop(pos_t, x ## __VA_ARGS__); \
+xprop(pos_t, y ## __VA_ARGS__); \
+auto & xy ## __VA_ARGS__( \
+ pos_t x, \
+ pos_t y){ \
+ this->x ## __VA_ARGS__(x); \
+ this->y ## __VA_ARGS__(y); \
+ return ((type *)this)[0]; \
+} \
+auto & xy ## __VA_ARGS__( \
+ pos_t * x, \
+ pos_t * y){ \
+ this->x ## __VA_ARGS__(x); \
+ this->y ## __VA_ARGS__(y); \
+ return ((type *)this)[0]; \
+} \
+auto & xy ## __VA_ARGS__(point p){ \
+ return xy ## __VA_ARGS__(p.x, p.y); \
+} \
+auto xy ## __VA_ARGS__(){ \
+ return point(x ## __VA_ARGS__(), y ## __VA_ARGS__()); \
+} \
+auto & xy ## __VA_ARGS__(point * p){ \
+ return xy ## __VA_ARGS__(& p->x, & p->y); \
+}
+
+#define xpositionx(struct_type,list,set,default_set) \
+struct_type() { \
+ _x = 0; \
+ _y = 0; \
+ default_set; \
+} \
+struct_type(pos_t x, pos_t y) : \
+ struct_type(){ \
+ _x = x; \
+ _y = y; \
+} \
+struct_type(point p) : \
+ struct_type(p.x, p.y) { \
+} \
+struct_type(point p, list) : \
+ struct_type(p.x, p.y) { \
+ set; \
+} \
+struct_type(pos_t x, pos_t y, list) : \
+ struct_type(x,y){ \
+ set; \
+} \
+
+
+#define xposition(struct_type,...) \
+struct_type() { \
+ _x = 0; \
+ _y = 0; \
+ __VA_ARGS__; \
+} \
+struct_type(pos_t x, pos_t y) : \
+ struct_type(){ \
+ _x = x; \
+ _y = y; \
+} \
+struct_type(point p) : \
+ struct_type(p.x, p.y) { \
+} \
+
+
+namespace detail {
+ template<class return_type>
+ struct poly{
+ poly(){
+ _color.push_back(pan_color);
+ _thickness.push_back(pan_thickness);
+ }
+ poly(std::initializer_list<point> const & value) :
+ poly(){
+ _value = value;
+ }
+ xvprop(point, value, (return_type *));
+ xvprop(color_t, color, (return_type *));
+ xvprop(pix_t, thickness, (return_type*));
+ };
+
+ template<class return_type>
+ struct aligner{
+ aligner() :
+ _x(0),
+ _y(0),
+ _width(0),
+ _height(0),
+ _origin(left),
+ _vorigin(top){
+ }
+ xpoint(return_type);
+ xprop(pix_t, width, (return_type*));
+ xprop(pix_t, height, (return_type*));
+ xprop(align_type, origin, (return_type*));
+ xprop(valign_type, vorigin, (return_type*));
+ //protected:
+ point adjust(pix_t width, pix_t height) {
+ auto x = _x;
+ auto y = _y;
+
+ if (_width == 0) {
+ _width = width;
+ }
+ if (_height == 0) {
+ _height = height;
+ }
+ if (_origin == center) {
+ x -= width / 2;
+ }
+ else if (_origin == right) {
+ x -= width;
+ }
+ if (_vorigin == vcenter) {
+ y -= height / 2;
+ }
+ else if (_vorigin == bottom) {
+ y -= height;
+ }
+ return point(x, y);
+ }
+ };
+}
+
+struct dot{
+ xposition(dot, {
+ _color = pan_color;
+ });
+ xpoint(dot);
+ xprop(color_t, color);
+ void draw();
+ operator can_drawable(){
+ return can_drawable(this);
+ }
+};
+
+struct line{
+ line(){
+ _x0 = 0;
+ _y0 = 0;
+ _x1 = 0;
+ _y1 = 0;
+ _thickness = 1;
+ _color = black;
+ }
+ line(point p0, point p1) :
+ line(p0.x, p0.y, p1.x, p1.y){
+ }
+ line(pos_t x0, pos_t y0, pos_t x1, pos_t y1):
+ line() {
+ _x0 = x0;
+ _y0 = y0;
+ _x1 = x1;
+ _y1 = y1;
+ }
+ xpoint(line, 0);
+ xpoint(line, 1);
+ xprop(color_t, color);
+ xprop(pix_t, thickness);
+ void draw();
+ operator can_drawable(){
+ return can_drawable(this);
+ }
+};
+
+struct rectangle;
+struct rectangle : detail::aligner<rectangle>{
+ xpositionx(
+ rectangle, xlist(pix_t width, pix_t height), {
+ _width = width;
+ _height = height;
+ }, {
+ _fill = transparent;
+ _color = pan_color;
+ _thickness_left = pan_thickness;
+ _thickness_top = pan_thickness;
+ _thickness_right = pan_thickness;
+ _thickness_bottom = pan_thickness;
+ });
+ xprop(color_t, fill);
+ xprop(color_t, color);
+ xprop(pix_t, thickness_left);
+ xprop(pix_t, thickness_top);
+ xprop(pix_t, thickness_right);
+ xprop(pix_t, thickness_bottom);
+ rectangle & thickness(pix_t all){
+ return thickness(all, all, all, all);
+ }
+ rectangle & thickness(pix_t left, pix_t top, pix_t right, pix_t bottom){
+ _thickness_left = left;
+ _thickness_top = top;
+ _thickness_right = right;
+ _thickness_bottom = bottom;
+ return this[0];
+ }
+ void draw();
+ operator can_drawable() {
+ return can_drawable(this);
+ }
+};
+
+struct dash_line;
+struct dash_line {
+ xpositionx(dash_line,
+ pix_t length, {
+ _length = length;
+ }, {
+ _length = 0;
+ _solid = 2;
+ _empty = 2;
+ _color = pan_color;
+ _thickness = pan_thickness;
+ _orientation = horizon;
+ });
+ xpoint(dash_line);
+ xprop(pix_t, length);
+ xprop(pix_t, empty);
+ xprop(pix_t, solid);
+ xprop(color_t, color);
+ xprop(pix_t, thickness);
+ xprop(::orientation, orientation);
+
+ void draw();
+ operator can_drawable(){
+ return can_drawable(this);
+ }
+};
+
+struct ellipse;
+struct ellipse : detail::aligner<ellipse> {
+ ellipse() :
+ detail::aligner<ellipse>(){
+ _color = pan_color;
+ _fill = transparent;
+ _thickness = pan_thickness;
+ _origin = center;
+ _vorigin = vcenter;
+ }
+ ellipse(pos_t x, pos_t y):
+ ellipse() {
+ _x = x;
+ _y = y;
+ }
+ ellipse(point p) :
+ ellipse(p.x, p.y) {
+ }
+ ellipse(point p, pix_t r) :
+ ellipse(p.x, p.y, r * 2, r * 2) {
+ }
+ ellipse(point p, pix_t width, pix_t height) :
+ ellipse(p.x, p.y, width, height) {
+ }
+ ellipse(pos_t x, pos_t y, pix_t r) :
+ ellipse(x, y, r * 2, r * 2) {
+ }
+ ellipse(pos_t x, pos_t y, pix_t width, pix_t height):
+ ellipse(x, y) {
+ _width = width;
+ _height = height;
+ }
+ xprop(color_t, color);
+ xprop(color_t, fill);
+ xprop(pix_t, thickness);
+
+ auto & r(pix_t value) {
+ _height = _width = value * 2;
+ return this[0];
+ }
+ void draw();
+ operator can_drawable() {
+ return can_drawable(this);
+ }
+protected:
+ point adjust(pix_t width, pix_t height) {
+ auto x = _x;
+ auto y = _y;
+
+ if (_width == 0) {
+ _width = width;
+ }
+ if (_height == 0) {
+ _height = height;
+ }
+ if (_origin == left) {
+ x += _width / 2;
+ }
+ else if (_origin == right) {
+ x -= _width / 2;
+ }
+ if (_vorigin == top) {
+ y -= _height / 2;
+ }
+ else if (_vorigin == bottom) {
+ y += _height / 2;
+ }
+ return point(x, y);
+ }
+};
+
+struct text;
+struct text : detail::aligner<text>{
+ xpositionx(text,
+ text_t value, {
+ _value = value;
+ }, {
+ _value = "";
+ _font = pix;
+ _font_size = 12;
+ _color = pan_color;
+ _align = left;
+ _valign = top;
+ _thickness = 1;
+ });
+private:
+ font_t _font;
+ pix_t _thickness;
+public:
+ text & font(font_t value);
+ font_t font(){
+ return _font;
+ }
+ text & thickness(pix_t value);
+ pix_t thickness(){
+ return _thickness;
+ }
+ xprop(pix_t, font_size);
+ xprop(color_t, color);
+ xprop(text_t, value);
+ xprop(align_type, align);
+ xprop(valign_type, valign);
+ text & font_height(pix_t * value);
+ text & content_width(pix_t * value);
+ pix_t font_height() {
+ pix_t height;
+ font_height(& height);
+ return height;
+ }
+ pix_t content_width() {
+ pix_t width;
+ content_width(& width);
+ return width;
+ }
+
+ void draw();
+ operator can_drawable(){
+ return can_drawable(this);
+ }
+};
+
+struct polyline;
+struct polyline : detail::poly<polyline>{
+ polyline(){}
+ polyline(std::initializer_list<point> data) :
+ detail::poly<polyline>(data){
+ }
+ void draw();
+ operator can_drawable() {
+ return can_drawable(this);
+ }
+};
+
+struct polygen;
+struct polygen : detail::poly<polygen>{
+ polygen() {}
+ polygen(std::initializer_list<point> data) :
+ detail::poly<polygen>(data) {
+ }
+ void draw();
+ operator can_drawable() {
+ return can_drawable(this);
+ }
+};
+
+
diff --git a/HelloWorld/seeed_graphics_define.h b/HelloWorld/seeed_graphics_define.h
new file mode 100644
index 0000000..00b3ae6
--- /dev/null
+++ b/HelloWorld/seeed_graphics_define.h
@@ -0,0 +1,102 @@
+#pragma once
+#define null16 32767
+#include<TFT_eSPI.h>
+#pragma push(max)
+#pragma push(min)
+#undef max
+#undef min
+#include<initializer_list>
+#include<list>
+#include<vector>
+#include<queue>
+#include<stdint.h>
+#pragma pop(min)
+#pragma pop(max)
+#include<string>
+
+typedef const char * text_t;
+typedef int16_t pos_t;
+typedef uint16_t pix_t;
+typedef uint32_t color_t;
+typedef std::queue<double> doubles;
+
+enum class font_t : uint16_t {};
+enum class align_type : uint8_t {};
+enum class valign_type : uint8_t {};
+enum class orientation : uint8_t {};
+
+constexpr orientation horizon = orientation(0);
+constexpr orientation vertical = orientation(1);
+
+constexpr align_type left = align_type(0);
+constexpr align_type center = align_type(1);
+constexpr align_type right = align_type(2);
+constexpr valign_type top = valign_type(0);
+constexpr valign_type vcenter = valign_type(1);
+constexpr valign_type bottom = valign_type(2);
+
+
+constexpr color_t black = 0x0000; /* 0, 0, 0 */
+constexpr color_t navy = 0x000F; /* 0, 0, 128 */
+constexpr color_t drakgreen = 0x03E0; /* 0, 128, 0 */
+constexpr color_t darkcyan = 0x03EF; /* 0, 128, 128 */
+constexpr color_t maroon = 0x7800; /* 128, 0, 0 */
+constexpr color_t purple = 0x780F; /* 128, 0, 128 */
+constexpr color_t olive = 0x7BE0; /* 128, 128, 0 */
+constexpr color_t lightgray = 0xC618; /* 192, 192, 192 */
+constexpr color_t darkgray = 0x7BEF; /* 128, 128, 128 */
+constexpr color_t gray = 0xCE79;
+constexpr color_t blue = 0x001F; /* 0, 0, 255 */
+constexpr color_t green = 0x07E0; /* 0, 255, 0 */
+constexpr color_t cyan = 0x07FF; /* 0, 255, 255 */
+constexpr color_t red = 0xF800; /* 255, 0, 0 */
+constexpr color_t magenta = 0xF81F; /* 255, 0, 255 */
+constexpr color_t yellow = 0xFFE0; /* 255, 255, 0 */
+constexpr color_t white = 0xFFFF; /* 255, 255, 255 */
+constexpr color_t orange = 0xFDA0; /* 255, 180, 0 */
+constexpr color_t greenyellow = 0xB7E0; /* 180, 255, 0 */
+constexpr color_t pink = 0xFC9F;
+constexpr color_t transparent = 0xFF000000;
+constexpr color_t pan_color = color_t(black);
+constexpr font_t pix = font_t(1);
+constexpr pix_t pan_thickness = 1;
+
+struct can_drawable {
+ typedef void (can_drawable::*invoke_t)();
+ typedef can_drawable * can_drawable_p;
+ template<class type>
+ can_drawable(type * obj){
+ invoke = invoke_t(& type::draw);
+ object = can_drawable_p(obj);
+ }
+ void draw(){
+ (object->*invoke)();
+ }
+private:
+ void empty(){}
+ invoke_t invoke;
+ can_drawable * object;
+};
+
+extern std::vector<color_t> classic_colors;
+
+struct point{
+ pos_t x;
+ pos_t y;
+ point():x(0), y(0){}
+ point(pos_t x, pos_t y):
+ x(x), y(y){
+ }
+ point operator()(const point & p){
+ return point{ this->x + p.x, this->y + p.y };
+ }
+ point operator()(pos_t x, pos_t y) {
+ return point{ this->x + x, this->y + y };
+ }
+ point operator + (point value) {
+ return point{ this->x + value.x, this->y + value.y };
+ }
+ point operator - (point value) {
+ return point{ this->x - value.x, this->y - value.y };
+ }
+};
diff --git a/HelloWorld/seeed_line_chart.h b/HelloWorld/seeed_line_chart.h
new file mode 100644
index 0000000..9b82460
--- /dev/null
+++ b/HelloWorld/seeed_line_chart.h
@@ -0,0 +1,422 @@
+#pragma once
+#include"seeed_graphics_base.h"
+#include"float.h"
+
+struct range {
+ double max_value;
+ double min_value;
+ size_t max_count;
+
+ template<class type>
+ range(type & list) {
+ max_value = 0;
+ min_value = 0;
+ max_count = 0;
+
+ if (list.size() == 0) {
+ return;
+ }
+
+ min_value = max_value = list[0].front();
+
+ for (size_t i = 0; i < list.size(); i++) {
+ if (max_count < list[i].size()) {
+ max_count = list[i].size();
+ }
+ for (size_t j = 0; j < list[i].size(); j++) {
+ if (max_value < list[i].front()) {
+ max_value = list[i].front();
+ }
+ else if (min_value > list[i].front()) {
+ min_value = list[i].front();
+ }
+ list[i].push(list[i].front());
+ list[i].pop();
+ }
+ }
+ }
+};
+
+struct match_tick {
+ double abs_value;
+ double top_value;
+ double start_value;
+ double step;
+ pix_t tick;
+
+ match_tick(
+ double max_value,
+ double min_value,
+ double based_on,
+ pix_t max_tick,
+ pix_t min_tick) {
+ constexpr bool found = true;
+ constexpr bool not_found = false;
+ double exp;
+ double val;
+ bool is_neg = false;
+ bool need_find = true;
+ int32_t max_val = 0;
+ int32_t min_val = 0;
+ auto min_step = { 5, 4, 2, 1 };
+ max_value -= based_on;
+ min_value -= based_on;
+ start_value = 0;
+ abs_value = 0;
+ top_value = 0;
+ tick = 0;
+ step = 0;
+
+ auto invoke = [&](int min_step){
+ min_val = int32_t(val) + 1;
+ max_val = min_val * 15 / 100 * 10; //1.510010
+ while (min_tick <= max_tick) {
+ while (max_val > min_val) {
+ if (max_val % min_tick == 0) {
+ tick = min_tick;
+ step = double(max_val / min_tick) * pow(10, -exp);
+ top_value = step * tick;
+ abs_value = top_value - start_value;
+ if (is_neg) {
+ start_value = -top_value;
+ top_value = 0;
+ }
+ min_tick = max_tick;
+ return found;
+ }
+ max_val -= 5;
+ }
+ min_tick++;
+ }
+ return not_found;
+ };
+
+ if (min_value >= 0) {
+ if (max_value <= 1) {
+ exp = round(-log10(max_value)) + 2;
+ }
+ else {
+ exp = -round(log10(max_value)) + 2;
+ }
+ val = max_value * pow(10, exp);
+
+ }
+ else if (max_value <= 0){
+ if (min_value >= -1) {
+ exp = round(-log10(-min_value)) + 2;
+ }
+ else {
+ exp = -round(log10(-min_value)) + 2;
+ }
+ is_neg = true;
+ val = -min_value * pow(10, exp);
+ }
+ else {
+ while(min_tick <= max_tick) {
+ for (double i = 1.0, j = 1; i < 1.5; i += 0.1) {
+ auto tmp = match_tick((max_value - min_value) * i, 0, 0, max_tick, min_tick);
+ min_tick++;
+
+ while (j * tmp.step < -min_value) {
+ j++;
+ }
+
+ auto start = j * tmp.step;
+ auto top = tmp.abs_value - start;
+
+ if (top >= max_value) {
+ abs_value = tmp.abs_value;
+ top_value = top;
+ start_value = -start;
+ step = tmp.step;
+ tick = tmp.tick;
+ min_tick = max_tick + 1;
+ break;
+ }
+ }
+ }
+ need_find = false;
+ }
+ if (need_find){
+ for (auto m : min_step){
+ if (invoke(m) == found){
+ break;
+ }
+ }
+ }
+ top_value += based_on;
+ start_value += based_on;
+ }
+};
+
+struct line_chart {
+ template<class list, class callback>
+ void draw_tick(
+ list & items,
+ size_t tick_count,
+ pix_t total_pix,
+ callback call) {
+ auto tick_step = 1.0 * items.size() / tick_count;
+ auto tick_pix_step = 1.0 * total_pix / tick_count;
+ auto tick_sum = 0.0;
+ auto tick_pix_sum = 0.0;
+
+ for (size_t i = 0; i <= tick_count; i++, tick_sum += tick_step, tick_pix_sum += tick_pix_step) {
+ auto index = size_t(round(tick_sum));
+ auto x = pos_t(round(tick_pix_sum));
+ call(i, x);
+ }
+ }
+public:
+ xpositionx(
+ line_chart,
+ xlist(pix_t width, pix_t height), {
+ _height = height;
+ _width = width;
+ }, {
+ _x_max_tick_count = 10;
+ _x_min_tick_count = 3;
+ _y_max_tick_count = 8;
+ _y_min_tick_count = 3;
+ _x_skip_tick = 0;
+ _tick = 8;
+ _x_auxi_role = dash_line().color(gray);
+ _x_role_color = pan_color;
+ _x_tick_color = pan_color;
+ _x_role_thickness = pan_thickness;
+ _y_role_color = pan_color;
+ _y_tick_color = pan_color;
+ _y_role_thickness = pan_thickness;
+ _format = "%g";
+ _color = classic_colors;
+ _show_circle = std::initializer_list<bool>{ true };
+ _based_on = 0;
+ });
+ xpoint(line_chart);
+ xprop(pix_t, height);
+ xprop(pix_t, width) ;
+ xprop(pix_t, x_max_tick_count);
+ xprop(pix_t, x_min_tick_count);
+ xprop(pix_t, y_max_tick_count);
+ xprop(pix_t, y_min_tick_count);
+ xprop(float, x_skip_tick);
+ xprop(pix_t, tick);
+ xprop(dash_line, x_auxi_role);
+ xprop(color_t, x_role_color);
+ xprop(color_t, x_tick_color);
+ xprop(pix_t, x_role_thickness);
+ xprop(color_t, y_role_color);
+ xprop(color_t, y_tick_color);
+ xprop(pix_t, y_role_thickness);
+ xprop(const char *, format);
+ xprop(double, based_on);
+
+private:
+ std::vector<color_t> _color;
+public:
+ template<class ... arg>
+ auto & color(color_t first, arg ... list){
+ _color = std::vector<color_t>{ first, list... };
+ return this[0];
+ }
+private:
+ std::vector<bool> _show_circle;
+public:
+ template<class ... arg>
+ auto & show_circle(bool first, arg ... list) {
+ _show_circle = std::vector<bool>{ first, list... };
+ return this[0];
+ }
+
+ xprop(std::vector<text_t>, note);
+private:
+ std::vector<doubles> _value;
+public:
+ auto & value(doubles const & list){
+ _value.clear();
+ _value.push_back(list);
+ return this[0];
+ }
+ auto & value(std::vector<double> const & list){
+ doubles que;
+ for(auto i : list){
+ que.push(i);
+ }
+ return value(que);
+ }
+ auto & value(std::vector<doubles> const & items){
+ _value = items;
+ return this[0];
+ }
+
+ void draw() {
+ //y/x
+ //x
+ auto y_tick_value_template = text().origin(right).vorigin(vcenter);
+ auto x_tick_value_template = text().origin(center).vorigin(top);
+ auto r = range(_value);
+ auto m = match_tick(r.max_value, r.min_value, _based_on, _y_max_tick_count, _y_min_tick_count);
+ auto w = pix_t(0);
+ auto max_y_tick_pix_width = 0;
+ char buf[256];
+ char * p = buf;
+ std::vector<text> y_tick_value;
+ for (size_t i = 0; i <= m.tick; i++, p += strlen(p) + 1) {
+ sprintf(p, _format, m.start_value + i * m.step);
+ y_tick_value.push_back(
+ text().value(p).origin(right).vorigin(vcenter).color(_y_tick_color).content_width(&w)
+ );
+ if (max_y_tick_pix_width < w) {
+ max_y_tick_pix_width = w;
+ }
+ }
+
+ //1.5 -> 0.5y 1.0x
+ auto x_extend_step = _value.size() != 0 ? 1.5 : 0.5;
+ auto y_extend_height = _tick + x_extend_step * x_tick_value_template.font_height();
+ auto y_extend_width = _tick + max_y_tick_pix_width;
+ auto x = _x + y_extend_width;
+ auto y = _y + 0.5 * x_tick_value_template.font_height();
+ auto width = _width - y_extend_width;
+ auto height = _height - y_extend_height;
+ auto origin = point(x, y + height);
+ auto y_start = origin(0, _tick);
+ auto y_end = origin(0, -(pos_t)height);
+ auto x_start = origin(-_tick, 0);
+ auto x_end = origin(width, 0);
+
+
+ if (_value.size()) draw_tick(_value, m.tick, height, [&](size_t i, pix_t y) {
+ auto p0 = origin(0, -(pos_t)y);
+ auto p1 = origin(-_tick, -(pos_t)y);
+
+ //
+ if (i != 0) {
+ _x_auxi_role.xy(p0).length(width).draw();
+ }
+
+ //
+ line(p0, p1).color(_x_tick_color).draw();
+ y_tick_value[i].xy(p1).draw();
+ });
+
+ //x
+ auto x_tick = std::min(_note.size(), size_t(_x_max_tick_count));
+ auto x_skip_half_tick = round(_x_skip_tick) > _x_skip_tick;
+ auto x_skip_tick = pix_t(_x_skip_tick);
+ auto x_tick_addition = x_skip_half_tick ? 0 : 1;
+ auto x_step = double(width) / (r.max_count + x_skip_tick - x_tick_addition);
+ auto x_offset = x_skip_half_tick ? x_step / 2 : 0;
+ auto x_tick_width = pix_t(x_step);
+
+ if (_note.size()) draw_tick(_note, x_tick + x_skip_tick - x_tick_addition, width, [&](size_t i, pix_t x) {
+ auto p0 = origin(x, 0);
+ auto p1 = origin(x, _tick);
+ line(p0, p1).color(_x_tick_color).draw();
+
+ if (i < x_skip_tick) {
+ return;
+ }
+
+ auto index = i - x_skip_tick;
+ auto p2 = p1(pix_t(x_offset), 0);
+
+ if (index >= _note.size()) {
+ return;
+ }
+
+ text(p2, _note[index])
+ .origin(center)
+ .width(x_tick_width)
+ .color(_x_tick_color)
+ .draw();
+ });
+
+ //
+ for (size_t i = 0; i < _value.size(); i++) {
+ doubles cur = _value[i];
+ auto default_color = _color[std::min(i, _color.size() - 1)];
+ auto show_circle = _show_circle[std::min(i, _show_circle.size() - 1)];
+ std::vector<point> value_point;
+
+ for(int j = 0; j < cur.size() - 1; j++){
+ cur.push(cur.front());
+ auto a = cur.front(); cur.pop();
+ auto b = cur.front();
+ auto ha = pos_t(round((a - m.start_value) / m.abs_value * height));
+ auto hb = pos_t(round((b - m.start_value) / m.abs_value * height));
+ auto pa = origin(pos_t((j + x_skip_tick) * x_step + x_offset), -(pos_t)ha);
+ auto pb = origin(pos_t((j + x_skip_tick + 1) * x_step + x_offset), -(pos_t)hb);
+ line(pa, pb).color(default_color).draw();
+ if (j == 0) {
+ value_point.push_back(pa);
+ }
+ value_point.push_back(pb);
+ }
+ if (show_circle) {
+ for (auto p : value_point) {
+ ellipse(p, 5, 5).color(default_color).fill(white).origin(center).vorigin(vcenter).draw();
+ }
+ }
+ }
+ line(x_start, x_end).color(_x_role_color).thickness(_x_role_thickness).draw();
+ line(y_start, y_end).color(_y_role_color).thickness(_y_role_thickness).draw();
+ }
+
+ operator can_drawable(){
+ return can_drawable(this);
+ }
+};
+
+// struct ring_chart {
+// xpositionx(
+// ring_chart,
+// xlist(pix_t r), {
+// _r = r;
+// }, {
+// _r = 0;
+// _angle_offset = 0;
+// _color = classic_colors;
+// _thickness.push_back(20);
+// });
+
+// xpoint(ring_chart);
+// xprop(pix_t, r);
+// xprop(float, angle_offset);
+// xvprop(color_t, color);
+// xvprop(pix_t, thickness);
+// xvprop(double, value);
+
+// void draw() {
+// if (_value.size() == 0) {
+// return;
+// }
+
+// auto color = _color.cbegin();
+// auto thickness = _thickness.cbegin();
+// auto sum = 0.0;
+// auto offset = _angle_offset;
+
+// for (auto v : _value) {
+// sum += v;
+// }
+// for (auto v : _value) {
+// auto angle = 360.0 * v / sum;
+// // ellipse(_x, _y, _r)
+// // .start_angle(offset)
+// // .end_angle(offset += angle)
+// // .color(*color)
+// // .thickness(*thickness)
+// // .draw();
+
+// if (++color == _color.cend()) {
+// color = _color.cbegin();
+// }
+// if (thickness + 1 != _thickness.cend()) {
+// thickness++;
+// }
+// }
+// }
+// };
+
+// #endif