mirror of
https://github.com/esphome/esphome.git
synced 2024-11-25 16:38:16 +01:00
Add triangle shapes to display component (#6096)
This commit is contained in:
parent
87cab92af6
commit
72ab1700e7
2 changed files with 131 additions and 0 deletions
|
@ -141,6 +141,122 @@ void Display::filled_circle(int center_x, int center_y, int radius, Color color)
|
||||||
}
|
}
|
||||||
} while (dx <= 0);
|
} while (dx <= 0);
|
||||||
}
|
}
|
||||||
|
void HOT Display::triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
|
||||||
|
this->line(x1, y1, x2, y2);
|
||||||
|
this->line(x1, y1, x3, y3);
|
||||||
|
this->line(x2, y2, x3, y3);
|
||||||
|
}
|
||||||
|
void Display::sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3) {
|
||||||
|
if (*y1 > *y2) {
|
||||||
|
int x_temp = *x1, y_temp = *y1;
|
||||||
|
*x1 = *x2, *y1 = *y2;
|
||||||
|
*x2 = x_temp, *y2 = y_temp;
|
||||||
|
}
|
||||||
|
if (*y1 > *y3) {
|
||||||
|
int x_temp = *x1, y_temp = *y1;
|
||||||
|
*x1 = *x3, *y1 = *y3;
|
||||||
|
*x3 = x_temp, *y3 = y_temp;
|
||||||
|
}
|
||||||
|
if (*y2 > *y3) {
|
||||||
|
int x_temp = *x2, y_temp = *y2;
|
||||||
|
*x2 = *x3, *y2 = *y3;
|
||||||
|
*x3 = x_temp, *y3 = y_temp;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Display::filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
|
||||||
|
// y2 must be equal to y3 (same horizontal line)
|
||||||
|
|
||||||
|
// Initialize Bresenham's algorithm for side 1
|
||||||
|
int s1_current_x = x1;
|
||||||
|
int s1_current_y = y1;
|
||||||
|
bool s1_axis_swap = false;
|
||||||
|
int s1_dx = abs(x2 - x1);
|
||||||
|
int s1_dy = abs(y2 - y1);
|
||||||
|
int s1_sign_x = ((x2 - x1) >= 0) ? 1 : -1;
|
||||||
|
int s1_sign_y = ((y2 - y1) >= 0) ? 1 : -1;
|
||||||
|
if (s1_dy > s1_dx) { // swap values
|
||||||
|
int tmp = s1_dx;
|
||||||
|
s1_dx = s1_dy;
|
||||||
|
s1_dy = tmp;
|
||||||
|
s1_axis_swap = true;
|
||||||
|
}
|
||||||
|
int s1_error = 2 * s1_dy - s1_dx;
|
||||||
|
|
||||||
|
// Initialize Bresenham's algorithm for side 2
|
||||||
|
int s2_current_x = x1;
|
||||||
|
int s2_current_y = y1;
|
||||||
|
bool s2_axis_swap = false;
|
||||||
|
int s2_dx = abs(x3 - x1);
|
||||||
|
int s2_dy = abs(y3 - y1);
|
||||||
|
int s2_sign_x = ((x3 - x1) >= 0) ? 1 : -1;
|
||||||
|
int s2_sign_y = ((y3 - y1) >= 0) ? 1 : -1;
|
||||||
|
if (s2_dy > s2_dx) { // swap values
|
||||||
|
int tmp = s2_dx;
|
||||||
|
s2_dx = s2_dy;
|
||||||
|
s2_dy = tmp;
|
||||||
|
s2_axis_swap = true;
|
||||||
|
}
|
||||||
|
int s2_error = 2 * s2_dy - s2_dx;
|
||||||
|
|
||||||
|
// Iterate on side 1 and allow side 2 to be processed to match the advance of the y-axis.
|
||||||
|
for (int i = 0; i <= s1_dx; i++) {
|
||||||
|
if (s1_current_x <= s2_current_x) {
|
||||||
|
this->horizontal_line(s1_current_x, s1_current_y, s2_current_x - s1_current_x + 1, color);
|
||||||
|
} else {
|
||||||
|
this->horizontal_line(s2_current_x, s2_current_y, s1_current_x - s2_current_x + 1, color);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Bresenham's #1
|
||||||
|
// Side 1 s1_current_x and s1_current_y calculation
|
||||||
|
while (s1_error >= 0) {
|
||||||
|
if (s1_axis_swap) {
|
||||||
|
s1_current_x += s1_sign_x;
|
||||||
|
} else {
|
||||||
|
s1_current_y += s1_sign_y;
|
||||||
|
}
|
||||||
|
s1_error = s1_error - 2 * s1_dx;
|
||||||
|
}
|
||||||
|
if (s1_axis_swap) {
|
||||||
|
s1_current_y += s1_sign_y;
|
||||||
|
} else {
|
||||||
|
s1_current_x += s1_sign_x;
|
||||||
|
}
|
||||||
|
s1_error = s1_error + 2 * s1_dy;
|
||||||
|
|
||||||
|
// Bresenham's #2
|
||||||
|
// Side 2 s2_current_x and s2_current_y calculation
|
||||||
|
while (s2_current_y != s1_current_y) {
|
||||||
|
while (s2_error >= 0) {
|
||||||
|
if (s2_axis_swap) {
|
||||||
|
s2_current_x += s2_sign_x;
|
||||||
|
} else {
|
||||||
|
s2_current_y += s2_sign_y;
|
||||||
|
}
|
||||||
|
s2_error = s2_error - 2 * s2_dx;
|
||||||
|
}
|
||||||
|
if (s2_axis_swap) {
|
||||||
|
s2_current_y += s2_sign_y;
|
||||||
|
} else {
|
||||||
|
s2_current_x += s2_sign_x;
|
||||||
|
}
|
||||||
|
s2_error = s2_error + 2 * s2_dy;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Display::filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color) {
|
||||||
|
// Sort the three points by y-coordinate ascending, so [x1,y1] is the topmost point
|
||||||
|
this->sort_triangle_points_by_y_(&x1, &y1, &x2, &y2, &x3, &y3);
|
||||||
|
|
||||||
|
if (y2 == y3) { // Check for special case of a bottom-flat triangle
|
||||||
|
this->filled_flat_side_triangle_(x1, y1, x2, y2, x3, y3, color);
|
||||||
|
} else if (y1 == y2) { // Check for special case of a top-flat triangle
|
||||||
|
this->filled_flat_side_triangle_(x3, y3, x1, y1, x2, y2, color);
|
||||||
|
} else { // General case: split the no-flat-side triangle in a top-flat triangle and bottom-flat triangle
|
||||||
|
int x_temp = (int) (x1 + ((float) (y2 - y1) / (float) (y3 - y1)) * (x3 - x1)), y_temp = y2;
|
||||||
|
this->filled_flat_side_triangle_(x1, y1, x2, y2, x_temp, y_temp, color);
|
||||||
|
this->filled_flat_side_triangle_(x3, y3, x2, y2, x_temp, y_temp, color);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void Display::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text) {
|
void Display::print(int x, int y, BaseFont *font, Color color, TextAlign align, const char *text) {
|
||||||
int x_start, y_start;
|
int x_start, y_start;
|
||||||
|
|
|
@ -236,6 +236,12 @@ class Display : public PollingComponent {
|
||||||
/// Fill a circle centered around [center_x,center_y] with the radius radius with the given color.
|
/// Fill a circle centered around [center_x,center_y] with the radius radius with the given color.
|
||||||
void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
|
void filled_circle(int center_x, int center_y, int radius, Color color = COLOR_ON);
|
||||||
|
|
||||||
|
/// Draw the outline of a triangle contained between the points [x1,y1], [x2,y2] and [x3,y3] with the given color.
|
||||||
|
void triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
|
||||||
|
|
||||||
|
/// Fill a triangle contained between the points [x1,y1], [x2,y2] and [x3,y3] with the given color.
|
||||||
|
void filled_triangle(int x1, int y1, int x2, int y2, int x3, int y3, Color color = COLOR_ON);
|
||||||
|
|
||||||
/** Print `text` with the anchor point at [x,y] with `font`.
|
/** Print `text` with the anchor point at [x,y] with `font`.
|
||||||
*
|
*
|
||||||
* @param x The x coordinate of the text alignment anchor point.
|
* @param x The x coordinate of the text alignment anchor point.
|
||||||
|
@ -532,6 +538,15 @@ class Display : public PollingComponent {
|
||||||
void do_update_();
|
void do_update_();
|
||||||
void clear_clipping_();
|
void clear_clipping_();
|
||||||
|
|
||||||
|
/**
|
||||||
|
* This method fills a triangle using only integer variables by using a
|
||||||
|
* modified bresenham algorithm.
|
||||||
|
* It is mandatory that [x2,y2] and [x3,y3] lie on the same horizontal line,
|
||||||
|
* so y2 must be equal to y3.
|
||||||
|
*/
|
||||||
|
void filled_flat_side_triangle_(int x1, int y1, int x2, int y2, int x3, int y3, Color color);
|
||||||
|
void sort_triangle_points_by_y_(int *x1, int *y1, int *x2, int *y2, int *x3, int *y3);
|
||||||
|
|
||||||
DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES};
|
DisplayRotation rotation_{DISPLAY_ROTATION_0_DEGREES};
|
||||||
optional<display_writer_t> writer_{};
|
optional<display_writer_t> writer_{};
|
||||||
DisplayPage *page_{nullptr};
|
DisplayPage *page_{nullptr};
|
||||||
|
|
Loading…
Reference in a new issue