10
« on: March 29, 2023, 05:25:31 PM »
Hi,
Here is a small example of one way to use edge strips to draw an arc.
We can post an explanation too of how it works when ready. The only dependency is that you need cos and sin functions.
When drawing an arc using stencilling, the edge strips provide a good way to shade in an angle. However, each one (top, bottom, left, right) generally only work well for associated 90 degree areas and so we need to use more than one to make this arc.
This is just a basic one but we have used this technique for various arc gauge styles. You can add a point to make the leading and training edges rounded etc or a large point on the leading edge depending on the style which you want. You can also add more error checking etc. to handle out of range values.
It takes in various parameters including the max angle, min angle and the active value which defines how much of the arc is filled in.
p.s. one way to see what is happening is to comment out the line which turns off the color updates EVE_COLOR_MASK(0, 0, 0, 0); and set a COLOR_RGB for each section.
Here is a small illustration attached showing how the centre circles, the wedge at the bottom and the four quadrant edge strips form a stencil which can then be colored in to make the active part of the arc.
Hope it helps,
BRT Community
void Custom_Widget_Arc_Gauge(uint16_t arc_centerx, uint16_t arc_centery, uint16_t arc_radius, uint16_t arc_thickness, uint32_t Arc_Active_Color, uint32_t Arc_Inactive_Color, uint16_t arc_min_limit, uint16_t arc_max_limit, uint16_t arc_value)
{
double arc_value_rad = 0;
uint16_t arc_activex = 0;
uint16_t arc_activey = 0;
double arc_min_limit_rad = 0;
uint16_t arc_start_x = 0;
uint16_t arc_start_y = 0;
double arc_max_limit_rad = 0;
uint16_t arc_end_x = 0;
uint16_t arc_end_y = 0;
//--------------------------------------------------------------------------------------------------------
// Process the angle data which will be used to make a uniform motion of the arc
//--------------------------------------------------------------------------------------------------------
// Ensure the value is within limits
if(arc_value > arc_max_limit)
arc_value = arc_max_limit;
if(arc_value < arc_min_limit)
arc_value = arc_min_limit;
//---------------------------------------------------------
// Calculate the angle in Radians for the Cos and Sin functions
// radians = ((degrees*pi)/180)
// For the arc which we will fill (the actual value of the arc gauge)
// Note: 0 degress is at the very bottom of the circle
if(arc_value > 180)
arc_value_rad = ((arc_value-180) * 3.14)/180;
else
arc_value_rad = (arc_value * 3.14)/180;
// For the min limit which can be for example at 20 degrees from the bottom
if(arc_min_limit > 180)
arc_min_limit_rad = ((arc_min_limit-180) * 3.14)/180;
else
arc_min_limit_rad = (arc_min_limit * 3.14)/180;
// For the max limit which can be for example at 340 degrees from the bottom
if(arc_max_limit > 180)
arc_max_limit_rad = ((arc_max_limit-180) * 3.14)/180;
else
arc_max_limit_rad = (arc_max_limit * 3.14)/180;
//---------------------------------------------------------
// Calculate the coordinates of the starting point, the gauge arc and the point at the tip of the arc
// for the arc gauge itself
arc_activex = (sin(arc_value_rad) * arc_radius);
arc_activey = (cos(arc_value_rad) * arc_radius);
// for the starting angle (the minimum value of the arc as it is normally not desired to be a full 360 deg circle)
arc_start_x = (sin(arc_min_limit_rad) * arc_radius);
arc_start_y = (cos(arc_min_limit_rad) * arc_radius);
// for the finishing angle (the maximum value of the arc as it is normally not desired to be a full 360 deg circle)
arc_end_x = (sin(arc_max_limit_rad) * arc_radius);
arc_end_y = (cos(arc_max_limit_rad) * arc_radius);
//--------------------------------------------------------------------------------------------------------
// Write to the stencil buffer and disable writing to the screen to make an invisible arc
//--------------------------------------------------------------------------------------------------------
// Set the stencil to increment and diasble writes to the screen
EVE_STENCIL_OP(EVE_STENCIL_INCR, EVE_STENCIL_INCR);
EVE_COLOR_MASK(0, 0, 0, 0);
// Draw concentric circles to form the stencil so that the arc has a unique stencil value and we can shade it later
EVE_BEGIN(EVE_BEGIN_POINTS);
// Outer circle makes the outer edge of the arc
EVE_POINT_SIZE(arc_radius*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
// Inner circle makes the inner edge of the arc
EVE_POINT_SIZE((arc_radius - arc_thickness)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_END();
//--------------------------------------------------------------------------------------------------------
// Draw the edge strips which will fill in the arc
//--------------------------------------------------------------------------------------------------------
// These are drawn per quadrant as each edge strip will only work well on an angle up to 90 deg
// 0 - 89 Deg
if((arc_value > 0) && (arc_value < 90))
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_B);
EVE_VERTEX2F(((arc_centerx - arc_start_x)*16), (arc_centery+arc_start_y)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx - arc_activex)*16), (arc_centery + arc_activey)*16);
}
else
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_B);
EVE_VERTEX2F(((arc_centerx - arc_start_x)*16), (arc_centery+arc_start_y)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx - arc_radius)*16), (arc_centery)*16);
}
// 90 - 179 deg
if((arc_value >= 90)&& (arc_value < 180))
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_L);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx - arc_activex)*16), (arc_centery - arc_activey)*16);
}
else if (arc_value > 90)
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_L);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery - arc_radius)*16);
}
// 180 - 269 deg
if((arc_value >= 180)&& (arc_value < 270))
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_A);
EVE_VERTEX2F(((arc_centerx-1)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx + arc_activex)*16), (arc_centery - arc_activey)*16);
}
else if (arc_value > 180)
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_A);
EVE_VERTEX2F(((arc_centerx-1)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx + arc_radius )*16), (arc_centery)*16);
}
// 270 - 359 deg
if((arc_value > 270)&& (arc_value < 360))
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_R);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx + arc_activex)*16), (arc_centery + arc_activey)*16);
}
else if (arc_value > 270)
{
// Edge strip to draw the arc
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_R);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery + arc_radius)*16);
}
// and finally draw a wedge shape at the bottom to ensure the inactive part of the arc is not coloured in
EVE_BEGIN(EVE_BEGIN_EDGE_STRIP_B);
EVE_VERTEX2F(((arc_centerx - arc_start_x)*16), (arc_centery + arc_start_y)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_VERTEX2F(((arc_centerx + arc_end_x)*16), (arc_centery + arc_end_y)*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
EVE_END();
//--------------------------------------------------------------------------------------------------------
// Draw a circle which will fill the arc
//--------------------------------------------------------------------------------------------------------
// Stop incrementing the stencil
EVE_STENCIL_OP(EVE_STENCIL_KEEP, EVE_STENCIL_KEEP);
// re-enable writes to the screen
EVE_COLOR_MASK(1, 1, 1, 1);
// For the Active arc area, only draw in areas with stencil == 3
EVE_STENCIL_FUNC(EVE_TEST_EQUAL, 3, 255);
EVE_BEGIN(EVE_BEGIN_POINTS);
EVE_COLOR_RGB( ((uint8_t)(Arc_Active_Color>>16)), ((uint8_t)(Arc_Active_Color>>8)), ((uint8_t)(Arc_Active_Color)));
EVE_POINT_SIZE(arc_radius*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
////////EVE_END();
// For the Inactive area of the arc, only draw in areas with stencil == 2
EVE_STENCIL_FUNC(EVE_TEST_EQUAL, 2, 255);
EVE_BEGIN(EVE_BEGIN_POINTS);
EVE_COLOR_RGB( ((uint8_t)(Arc_Inactive_Color>>16)), ((uint8_t)(Arc_Inactive_Color>>8)), ((uint8_t)(Arc_Inactive_Color)));
EVE_POINT_SIZE(arc_radius*16);
EVE_VERTEX2F(((arc_centerx)*16), (arc_centery)*16);
////////EVE_END();
EVE_END();
//--------------------------------------------------------------------------------------------------------
// Clean up to avoid affecting other items later in the display list
//--------------------------------------------------------------------------------------------------------
EVE_STENCIL_FUNC(EVE_TEST_ALWAYS, 1, 255); // Revert to always drawing for the subsequent items
EVE_CLEAR(0,1,0); // Clear the stencil buffer to ensure it does not affect other items on the screen
}
//###############################################################################################################################################################
//###############################################################################################################################################################
void eve_display(void)
{
uint16_t arc_value = 40; // actual value
uint8_t direction = 0; // 0 means count up
while(1)
{
EVE_LIB_BeginCoProList(); // Begin new screen
EVE_CMD_DLSTART(); // Tell co-processor to create new Display List
EVE_CLEAR_COLOR_RGB(0x00, 0x55, 0xFF); // Specify color to clear screen to
EVE_CLEAR(1,1,1); // Clear color, stencil, and tag buffer
EVE_COLOR_RGB(255, 255, 255);
EVE_CMD_NUMBER(200, 200, 30, EVE_OPT_CENTERX, arc_value); // Print numerical arc value
EVE_COLOR_RGB(255, 255, 255);
// position Diam Arc Arc color Arc color ----values------
// active backgnd limit arc
// X Y Size width RRGGBB RRGGBB min max value
Custom_Widget_Arc_Gauge(200, 200, 180, 30, 0xFF6000, 0x800080, 40, 320, arc_value);
EVE_DISPLAY(); // Tell EVE that this is end of list
EVE_CMD_SWAP(); // Swap buffers in EVE to make this list active
EVE_LIB_EndCoProList(); // Finish the co-processor list burst write
EVE_LIB_AwaitCoProEmpty(); // Wait until co-processor has consumed all commands
if(direction == 0)
{
arc_value ++;
if(arc_value == 320)
direction = 1; // count down next time
}
else
{
arc_value --;
if(arc_value == 40)
direction = 0; // count up next time
}
}
}