How do I draw an arc? #1740
Replies: 5 comments 5 replies
-
It is possible. U8g2 includes a pixel draw procedure: You can draw the individual pixels of the arc.
You have to write a procedure which derives the pixel coordinates.
Yes, you can post it here or create a pull request. Note: The pixel conversion of an arc with variable width is a research problem. It is a challenge to reduce code size and execution time. |
Beta Was this translation helpful? Give feedback.
-
Here is a pseudo code (very slow performance with many open questions) for(t = start_angle; t <= end_angle; t += delta)
{
x = cos(t) * radius + x_center_pos;
y = sin(t) * radius + y_center_pos;
draw_disc(x, y, width);
} |
Beta Was this translation helpful? Give feedback.
-
thank you very much. |
Beta Was this translation helpful? Give feedback.
-
I have already solved this problem, maybe not in the most optimal way. |
Beta Was this translation helpful? Give feedback.
-
Hello! I had the same feature request, so implemented the Andres circle algorithm, which I adapted to include arc features. This algorithm is quite effective, as it sets each pixel only once, and can run with no floating points and no trigonometric function (in this case an approximation for the number of pixels drawn has to be made, so the arc edge can be noisy on large arc widths/radius: it can be annoying for some use cases, but if you make an animated spinner it is ok...) I made a JavaScript version so you can test it and see for yourself here: https://motla.github.io/arc-algorithm/ C implementation for u8g2It is just a proposal. u8g2_arc.h#ifndef U8G2_ARC_H
#define U8G2_ARC_H
#include "u8g2.h"
typedef float (*u8g2_atan2f_t)(float, float);
void u8g2_DrawArc(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad_in, u8g2_uint_t rad_out, u8g2_uint_t angle_start, u8g2_uint_t angle_end, u8g2_atan2f_t atan2f_func);
#endif // U8G2_ARC_H u8g2_arc.c#include "u8g2_arc.h"
static const float M_PI_2 = 1.57079632679489661923;
static const float M_PI_4 = 0.78539816339744830962;
static void u8g2_draw_arc(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad_in, u8g2_uint_t rad_out, u8g2_uint_t angle_start, u8g2_uint_t angle_end, u8g2_atan2f_t atan2f_func)
{
// Declare variables
u8g2_long_t x, y, d, r, as, ae, cnt, num_pts;
// Manage angle inputs
if(angle_start == angle_end) return;
uint8_t inverted = (angle_start > angle_end);
as = inverted ? angle_end : angle_start;
ae = inverted ? angle_start : angle_end;
// Trace each arc radius with the Andres circle algorithm
for(r = rad_in; r <= rad_out; r++)
{
x = 0;
y = r;
d = r - 1;
cnt = -1;
num_pts = atan2f_func ? 100 : (r * 8 / 10); // if no atan2f() function is provided, we make a low cost approximation of the number of pixels drawn for a 1/8th circle of radius r
// Process each pixel of a 1/8th circle of radius r
while (y >= x)
{
// If atan2f() function is provided, get the percentage of 1/8th circle drawn, otherwise count the drawn pixels
cnt = atan2f_func ? ((M_PI_2 - atan2f_func(y, x)) * 100 / M_PI_4) : (cnt + 1);
// Fill the pixels of the 8 sections of the circle, but only on the arc defined by the angles (start and end)
if((cnt > num_pts * as / 45 && cnt <= num_pts * ae / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 + y, y0 - x);
if((cnt > num_pts * (90 - ae) / 45 && cnt <= num_pts * (90 - as) / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 + x, y0 - y);
if((cnt > num_pts * (as - 90) / 45 && cnt <= num_pts * (ae - 90) / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 - x, y0 - y);
if((cnt > num_pts * (180 - ae) / 45 && cnt <= num_pts * (180 - as) / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 - y, y0 - x);
if((cnt > num_pts * (as - 180) / 45 && cnt <= num_pts * (ae - 180) / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 - y, y0 + x);
if((cnt > num_pts * (270 - ae) / 45 && cnt <= num_pts * (270 - as) / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 - x, y0 + y);
if((cnt > num_pts * (as - 270) / 45 && cnt <= num_pts * (ae - 270) / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 + x, y0 + y);
if((cnt > num_pts * (360 - ae) / 45 && cnt <= num_pts * (360 - as) / 45) ^ inverted) u8g2_DrawPixel(u8g2, x0 + y, y0 + x);
// Run Andres circle algorithm to get to the next pixel
if (d >= 2 * x)
{
d = d - 2 * x - 1;
x = x + 1;
} else if (d < 2 * (r - y))
{
d = d + 2 * y - 1;
y = y - 1;
} else
{
d = d + 2 * (y - x - 1);
y = y - 1;
x = x + 1;
}
}
}
}
void u8g2_DrawArc(u8g2_t *u8g2, u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad_in, u8g2_uint_t rad_out, u8g2_uint_t angle_start, u8g2_uint_t angle_end, u8g2_atan2f_t atan2f_func)
{
/* check for bounding box */
#ifdef U8G2_WITH_INTERSECTION
{
if ( u8g2_IsIntersection(u8g2, x0-rad_out, y0-rad_out, x0+rad_out+1, y0+rad_out+1) == 0 )
return;
}
#endif /* U8G2_WITH_INTERSECTION */
/* draw arc */
u8g2_draw_arc(u8g2, x0, y0, rad_in, rad_out, angle_start, angle_end, atan2f_func);
} UsageAngles are between 0 and 360 degree. Fast approximation mode#include "u8g2.h"
#include "u8g2_arc.h"
u8g2_DrawArc(&u8g2, 30, 30, 12, 16, 0, 300, NULL); Precision mode#include <math.h>
#include "u8g2.h"
#include "u8g2_arc.h"
u8g2_DrawArc(&u8g2, 30, 30, 12, 16, 0, 300, atan2f); If you have a DSP, you can provide its |
Beta Was this translation helpful? Give feedback.
-
Hi.
Happy New Year, everyone!!!
Is it possible to draw an arc of any size? How can I do that?
If there is no such function, is it possible to integrate such a function into your library?
I guess it should be like this:
void U8G2::drawArc(u8g2_uint_t x0, u8g2_uint_t y0, u8g2_uint_t rad, u8g2_uint_t line width, u8g2_uint_t starting angle, u8g2_uint_t end angle)
Beta Was this translation helpful? Give feedback.
All reactions