2025-01-14 01:23 AM
Hello!
I’ve been working on a project where I need to draw lines on the display using TouchGFX. I’ve managed to get a working solution with the help of TouchGFX's Graph code, but I wanted to share the code with you all to see if anyone has any suggestions for optimization.
Here’s the current code I’m using:
bool TestWidget::drawCanvasWidget(const touchgfx::Rect& invalidatedArea) const
{
if (numPoints < 2)
{
return true; // Not enough points to draw anything
}
touchgfx::Canvas canvas(getPainter(), getAbsoluteRect(), invalidatedArea, 255);
for (int i = 0; i < numPoints - 1; ++i)
{
drawSegment(canvas, points[i], points[i + 1]);
}
return canvas.render();
}
void TestWidget::drawSegment(touchgfx::Canvas& canvas, const Point& start, const Point& end) const
{
// Points for the current segment
float x0 = static_cast<float>(start.x);
float y0 = static_cast<float>(start.y);
float x1 = static_cast<float>(end.x);
float y1 = static_cast<float>(end.y);
// Calculate slope and perpendicular offsets for thickness
float dx = x1 - x0;
float dy = y1 - y0;
float length = std::sqrt(dx * dx + dy * dy);
float offsetX = 0.0f, offsetY = 0.0f;
if (length > 0.1f) // Avoid division by zero and handle very short lines
{
float scale = (lineWidth / 2.0f) / length;
offsetX = -scale * dy; // Perpendicular x offset
offsetY = scale * dx; // Perpendicular y offset
}
// Draw trapezoid for the current line segment
canvas.moveTo(x0 + offsetX, y0 + offsetY); // Top-left of the segment
canvas.lineTo(x1 + offsetX, y1 + offsetY); // Top-right of the segment
canvas.lineTo(x1 - offsetX, y1 - offsetY); // Bottom-right of the segment
canvas.lineTo(x0 - offsetX, y0 - offsetY); // Bottom-left of the segment
canvas.lineTo(x0 + offsetX, y0 + offsetY); // Close the shape
}
Additionally, it would be great if TouchGFX could enhance the canvas to include a function like drawLine. If there’s any way to achieve this with the current functionality, or if anyone has a more efficient approach to line drawing, I’d love to hear your thoughts!
P.S.: I'm currently performing calculations within the drawCanvasWidget function because, in the long run, I want to draw up to ~150,000 points. Any tips on optimizing performance for this scale would be greatly appreciated.
Thanks in advance for your help and suggestions!
2025-02-18 04:52 AM - edited 2025-02-18 04:58 AM
Hello TerZer,
Thanks for sharing the code. I'm working on a similar project with multiple lines, and I'm also missing a simple TouchGFX function to draw a line from A to B with a specified thickness.
Have you found a more optimal solution than CanvasWidget with moveTo() and lineTo() functions?
I will also ask if you had any problems with anti-aliasing other widgets over the CanvasWidget layer? I tried using CanvasWidget but there were glitches that I couldn't deal with. Like in the attached graphic where you can see the blue shape in CanvasWidget, and where the Widget is transparent, the text rendered over it loses the alpha channel.
In the end, in my project I used line drawing directly on the graphics buffer following the Dynamic Bitmap example (https://support.touchgfx.com/docs/development/ui-development/touchgfx-engine-features/dynamic-bitmaps) .
I draw the line using the Wu-based algorithm. However, drawing perfect lines of different thicknesses with anti-aliasing is not so easy. When I rotate an image composed of many lines at some angles the lines become noticeably thicker or narrower which does not meet the requirements.
If anyone has a proven line drawing algorithm that can be easily applied in embedded I would appreciate it if you share.
2025-02-19 04:15 AM
Hello @KamilTw ,
I recently replaced my code with VectorRenderer (API Reference), and I noticed a significant performance improvement compared to using CanvasWidget in my case.