wctltya Posted November 10, 2016 Report Posted November 10, 2016 Hi, I'm struggling to develop an algorithm to render a ring. Two concentric circles with a filled area between them. Already spent several days, but ... So, I'll appreciate if someone could help me. The easiest (obvious) approach drawing a number of circles doesn't work because there are many unfilled pixels, between them. That is obvious as well and is a consequence of the digitization. My function is based on the Midpoint Circle Algorithm https://en.wikipedia.org/wiki/Midpoint_circle_algorithm as uGFX draw/fill circle functions are based as well. The FillRing algorithm draws lines instead of dots only, trying to calculate the start and end points. For most of the lines is easy, but for some of them is not. The troubles appears when the circles (drawing) are in a different octets, excepts the top/bottom part (defined by r_out - r_in), which is the easiest part.
Joel Bodenmann Posted November 10, 2016 Report Posted November 10, 2016 Hi, We certainly can't help you without you providing your algorithm. If it's a small issue we might be able to help you or to give you certain pointers. Developing a dedicated algorithm for this is definitely the right approach as assembling the ring from other existing primitives will result in issues as you mentioned. Depending on your application / use-case you might be able to use the new gdispDrawDualCircle() function that was added 17 hours ago:
inmarket Posted November 11, 2016 Report Posted November 11, 2016 As you found the trick is when the octants change. Even if the gdispFillDualCircle() is not suitable you should be able to derive something from it that will work for you. gdispFillDualCircle() also uses (a variant optimisation of) the Midpoint algorithm so it is very fast.
wctltya Posted November 11, 2016 Author Report Posted November 11, 2016 Joel, inmarket Thank you very much. The gdispDrawDualCircle() is exactly what I was looking for . In order to make it exactly FillRing(), I just removed the third line in the #define DRAW_DUALLINE(yval, r1, r2), i.e. "g->p.x = x-r2; g->p.x1 = x+r2; g->p.color = color2; hline_clip(g); \" and it was done. But what about the definition in gdisp.h void gdispGFillDualCircle(GDisplay *g, coord_t x, coord_t y, coord_t radius1, color_t color1, coord_t radius2, color_t color2); #define gdispFillDualCircle(x,y,r,c) gdispGFillDualCircle(GDISP,x,y,r1,c1,r2,c2) I think it shall be #define gdispFillDualCircle(x,y,r1,c1,r2,c2) gdispGFillDualCircle(GDISP,x,y,r1,c1,r2,c2) isn't it? And I noticed extra pixels on the poles(E, S, W, N) of the both circles. The inner has on East and West only, perhaps the North and South are covered by top and bottom part of the outer circle. So, I drew two circles over the ring using the midpoint algorithm. Attached is the function and both pictures. Sorry for the pictures bad quality, but the differences are clearly visible. Ring.zip
inmarket Posted November 11, 2016 Report Posted November 11, 2016 You are right about the macro. We will fix that asap. Yes this is not exactly the midpoint algorithm. This is a first rather than a second derivative using the same reasoning. It is slightly less accurate than the midpoint algorithm however even the µGFX circle algorithm is not quite right either. In practice the true midpoint algorithm has some visual anomalies when rendered on low resolution screens that relate to the way integer rounding works. The µGFX circle algorithm has made some accuracy compromises in order to avoid those issues but is still very close to the midpoint algorithm. The reason the ring uses a different algorithm again is that swapping the quadrants would require a square root operation to do it properly. By making a slight compromise on accuracy we avoid that expensive computation. At some point in the future I may look at performing the same work on the ring code that was performed on the µGFX general circle algorithm but that is definitely not high priority. It is very time consuming to adjust that pixel here and there to get the best looking result at a range of sizes and resolutions.
Joel Bodenmann Posted November 11, 2016 Report Posted November 11, 2016 6 hours ago, inmarket said: You are right about the macro. We will fix that asap. Just fixed that: https://git.ugfx.io/uGFX/uGFX/commit/c91f42ec85a2c2f127663c0b0a9f11f11a6660b8
wctltya Posted November 14, 2016 Author Report Posted November 14, 2016 I see inmarket. But the nowadays embedded systems normally are powerful enough. Especially in terms of calculating power/speed. For example my system is with cortex-m4 at 120MHz and integrated floating point. Might be better if there is an option to choose better presentation at the corresponding resources cost of course. So, are you not eager to make the ring a progress bar/slider?
Joel Bodenmann Posted November 14, 2016 Report Posted November 14, 2016 Note that having a powerful processor doesn't mean that you can use the available resources for the GUI. There are more than plenty systems out there that run µGFX on very powerful & capable hardware that benefit from the fact that µGFX uses only a very small part of those resources so the rest is available to the actual job done (the stuff other than the GUI). 11 minutes ago, wctltya said: So, are you not eager to make the ring a progress bar/slider? We are working on that. That's why @inmarket wrote that new gdispGFillDualCircle() in first place.
wctltya Posted November 14, 2016 Author Report Posted November 14, 2016 3 minutes ago, Joel Bodenmann said: Note that having a powerful processor doesn't mean that you can use the available resources for the GUI. Sure, but in my particular case it is a dedicated HMI, so a communication with the main system is the only tasks run a side of the GUI. 5 minutes ago, Joel Bodenmann said: We are working on that. That's why @inmarket wrote that new gdispGFillDualCircle() in first place That is a very nice news. Can't wait to have it.
inmarket Posted November 14, 2016 Report Posted November 14, 2016 With drawing algorithms we generally code for the lowest common denominator. ie. integer algorithms with as few multiply and divides as possible. To have a seperate "expensive" version just does not make sense. It is twice the code, twice the potential bugs, twice the maintenance etc. If and when we spend more time on it, it will be to improve the accuracy for all platforms. The issues identified are around the integer approximation and its interaction with the midpoint algorithm (note the x axis end-points that you commented on). For the ring you also need the corresponding reverse derivitive approximation for when the octants are not aligned between the two circles. We would really love it if you had time to look at this for us. Unfortunately we just have too much on our development agenda to look at improving this anytime soon.
Recommended Posts
Create an account or sign in to comment
You need to be a member in order to leave a comment
Create an account
Sign up for a new account in our community. It's easy!
Register a new accountSign in
Already have an account? Sign in here.
Sign In Now