Because I started the thread I'll set the standard. Criteria: Must be an ellipse, must not overdraw pixels so as to not confound transparency. The best function will do the same thing faster. Here I used some LINEs and a nice fat LINE ()-(), , BF to get the job done, but on another thread I used only one LINE in repetition. Not even sure if this is better yet...
(If you're wondering where the SQR2(2) factors come from, it's from calculus of variations. It turns out that the biggest rectangle that fits in a quarter-ellipse has dimensions a/sqr(2) by b/sqr(2), making my choice of LINE ()-(), , BF ideal if you're going to consider patching a rectangle in first...)
This makes me think wonder if the size of the ellipse you draw might have a bearing on which function fills it fastest, regarding line the BF method vs lots of skinny lines. Make sure any test you do accounts for this. (Test lots of sizes)Code: QB64: [Select]
EDIT
Out of the box, Steve's version (that either he or bplus will inevitably post) is twice as fast. I'm trying to figure if it has something to do with calls to SQR...
Did you find Bresenham?
This might or might not be Steve's?
My understanding is that instead of doing a Quadrant's worth of calculations, it only does an Octant's worth (at least for the Circle Fill version) and yes, avoid ^, trig and SQR functions helps too.
It magically was on my drive, so the original author is unknown to me. (It may have even been me; I don’t know.) After I dug it up, I played around with it, noticed the similarities to CircleFill, and identified a few glitches. Optimizing those out was entirely my own work, back in November, and it became as you see it now — a routine which can draw ellipses just as fast as we used to be able to draw circles. ;)
It magically was on my drive, so the original author is unknown to me. (It may have even been me; I don’t know.) After I dug it up, I played around with it, noticed the similarities to CircleFill, and identified a few glitches. Optimizing those out was entirely my own work, back in November, and it became as you see it now — a routine which can draw ellipses just as fast as we used to be able to draw circles. ;)
maybe this will jog your memory:Code: QB64: [Select]
why are you using e + e instead of 2*e or -ry - ry instead of -2*ry? Can we learn more about these advanced optimization techniques?
Your attention to detail is indispensible plus! I wonder it the algorithm can be torn apart to find out why that happens... The thing seems to be *so* optimized that it became fragile. As soon as I get near a PC I will join your efforts...
Did you check what I posted above about switching up some of the math calcs? I don't want such a change to impede the speed.
Pete
That's what I wanted to know.
So, my fix applied with the fastest math method according to Steve would be...Code: QB64: [Select]
_TITLE "Ellipsefill from Steve" 'B+ 2019-02-10 resave this code to 'just test this code for proper filling without overlap, timed tests are else where k$ = "" _LIMIT 1 ' with Steve's EllipseFill, who needs CircleFill? fix for 0 radii 2019-02-05 ' Is this fast enough for general circle fill (June 2018): https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942 ' EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506 a = 2 * rx * rx b = 2 * ry * ry x = rx xx = ry * ry * (1 - rx - rx) yy = rx * rx sx = b * rx y = y + 1 sy = sy + a e = e + yy yy = yy + a x = x - 1 sx = sx - b e = e + xx xx = xx + b oldy = y ' Pete's fix. Get the last fill position. x = 0 y = ry xx = rx * ry yy = rx * rx * (1 - ry - ry) e = 0 sx = 0 sy = a * ry x = x + 1 sx = sx + b e = e + xx xx = xx + b y = y - 1 sy = sy - a e = e + yy yy = yy + a
a = 2 * rx * rx
to a = rx*rx + rx*rx
I just ran the timed test in a 32 bit version of QB64 and saved almost 3 sec on both CircleFill and EllipseFill.
Ha! go figure.
Aaaalrighty, didn't expect to be gone all day, so I'm trying to play catchup here. First thing I notice is Steve's function doesn't draw ellipses for large eccentricity (small b). There are boobs on each end - just a recent artifact or was that there all along?
100% regardless of this issue or any others, I think the situation demands a pencil-to-paper derivation of how that function works. I'll reinvent it all if I have to, but surely it's among Steve's notes somewhere?
So what Steve is saying is that...
...
R * R is faster than R ^ 2
...
Pete
And now, if he did it for octant instead of just quadrant, we would have something that looks like Steves code, after we also replaced the For loops with While loops since For loops are known to be slowest Loop structure.
We already went over LONG won't work. Just try this...
FlatEllipseFill 915, 305, 400, 200, _RGBA32(0, 100, 0, 40)
That's not an ellipse with LONG variable types, but it becomes an ellipse if you use DOUBLE variable types. I haven't looked into the number results to see where the number results fail. Hopefully, it's not some bug in QB64, but get this, 202, a larger number, works! I just don't have much patience when it comes to puzzles I guess, especially when I can skip right to a solution.
So if it is as fast using DOUBLE, great. If not, that's an issue. Maybe it can be fixed to use LONG by using SQR, or finding out what's wrong with LONG. I'll let you guys determine that, if you wish.
Pete
further optimized version of steve's amazing algorithm ;-)
comment out the last line in the sub ;-)Code: QB64: [Select]
a = 2*rx*rx b = 2*ry*ry x = 0 y = ry dx = ry*ry dy = rx*rx*(1 - 2*ry) e = 0 sx = 0 sy = a*ry x = x + 1 sx = sx + b e = e + dx dx = dx + b y = y - 1 sy = sy - a e = e + dy dy = dy + a x1 = x0 - x x2 = x0 + x y1 = y0 - y x = rx y = 0 dx = ry*ry*(1 - 2*rx) dy = rx*rx e = 0 sx = b*rx sy = 0 x3 = x0 - x y = y + 1 sy = sy + a e = e + dy dy = dy + a x = x - 1 sx = sx - b e = e + dx dx = dx + b
Hi Mark,
Did you see the one I just posted? I think I figured out a way to optimize it so we lose that inner loop and a couple of variables and lines.
Oh, even in the earlier versions I posted, I did take into consideration your don't draw it if height and/or width is zero. This line exits the sub routine if that happens...
IF a = 0 OR b = 0 THEN EXIT SUB
So yes, that is handled.
What I'm looking at now is a way to bypass multiple DIM reads when more than one ellipse is built in a routine...
Pete
Try the one in my last post. It bypasses reading DIMs after the first time, which should speed up results. If it still isn't faster, wow, could the progressive loops be faster than the square root calculation? That would be weird.
Pete
Reading DIMs aren’t an issue as they’re more QB64-side than C-translated side. Your compiled program won’t really notice a difference. ;)
Reading DIMs aren’t an issue as they’re more QB64-side than C-translated side. Your compiled program won’t really notice a difference. ;)
Anyway, what do you guys think GOTO vs DO/LOOP will win out in a speed test?
My system is Windows 10 64 bit laptop, intel core i5
Running tests on QB64, 32 bit version
circle Fill Pete's Fill
14.3945 14.5039
14.3945 14.3984
14.2891 14.3945
14.2851 14.3984
14.3945 14.4039
circle Fill STATIC Fill mod B+
14.2305 14.4531
14.2891 14.4492
14.3945 14.4531
14.1758 14.3984
14.2305 14.3984
Running tests on QB64, 64 bit version
circle Fill Pete's Fill
16.8672 17.0313
16.9258 16.8672
16.8125 16.9219
16.8125 16.8125
16.8711 17.0352
circle Fill STATIC Fill mod B+
16.9219 16.9766
16.9258 16.9766
16.8164 16.8711
16.8125 16.8672
16.8125 16.8125
SUB CircleFill (x, y, r, c)
EllipseFill x, y, r, r, c
END SUB
Ha! will it ever end?
Yep, I was expecting a flat ellipse with xRadius of n to be 2n pixels wide not 2n+1, likewise an ellipse with yRadius of m pixels to be 2m pixels high not 2m+1.
As I would expect a circle of r radius to be 2r wide and high.
Wouldn't a circle of radius 1 fill pixels (probably would have to round up) like this:
**
**
where is (x, y) origin? x+.5, y+.5?
not like this?
*
***
*
but x, y origin is obvious middle dot.
I think it would depend on how things round out, whether there is 1 dot at top and bottom or several.
Ha! will it ever end?
Yep, I was expecting a flat ellipse with xRadius of n to be 2n pixels wide not 2n+1, likewise an ellipse with yRadius of m pixels to be 2m pixels high not 2m+1.
As I would expect a circle of r radius to be 2r wide and high.
Wouldn't a circle of radius 1 fill pixels (probably would have to round up) like this:
**
**
where is (x, y) origin? x+.5, y+.5?
not like this?
*
***
*
but x, y origin is obvious middle dot.
I think it would depend on how things round out, whether there is 1 dot at top and bottom or several.
Isn’t a 1-radius circle just a point?
*
Or would you call that 0-radius with 1-radius being:
*
***
*
Enquiring minds want to know!
Personally, I’d think a radius of 2 should give a Diameter of 4, not 5, as these calculations are doing.
In the current models, Mark has an EXIT SUB, which prevents 0 from making any line or dot. Remove that, and a zero passed to the sub would result in a single line or dot, depending on the width measurement. In other words, 0, 0 would result in a dot, if Mark's EXIT SUB was removed.Pete, OK draw the pixel or line then.
Pete
Going once, going twice... SOLD on regular ellipses and circles.
One last question for bplus, about the modified tilted ellipse routine... Do we still need the first argument in this function? It's not referenced inside the SUB at all.Code: QB64: [Select]
mx2 = max + max _DEST tef& _SOURCE tef& 'point wont read without this! lasti = i: lastj = j x = 0 x = x + 1 xleft(y) = x x = x + 1 x = x + 1 _DEST destHandle& _FREEIMAGE tef&
These lines seem odd to me:
I suppose the best solution it to just draw the thing, PAINT the inside like I did a few pages ago, and let the user place that on screen using image handles.
Again I say, can we do something with QB64 CIRCLE routine ie add fills to what it already does?
OK maybe one of these days I will dig into the Source Code...
In meantime, I am keeping CircleFill in my tool box...
...and IMO it should go in the forum's as the number 1 entry!
If I really need speedier Flat Ellipses then STATIC's fudge of Pete's variation will do fine!
But I am trying to imagine Titled Ellipse No Fill, it could be draw directly to source no fooling around with isolated drawing. So build a switch onto Tilted Ellipse Fill or a whole separate sub? This is the question that remains for me because the requirements are so different.
For the record, Titled Ellipse Fill does not compare well with CIRCLE with same radius as a and aspect b/a. Look at what happens when b exceeds a! but I am supposed to switch radius for CIRCLE when b > a.
QuoteFor the record, Titled Ellipse Fill does not compare well with CIRCLE with same radius as a and aspect b/a. Look at what happens when b exceeds a! but I am supposed to switch radius for CIRCLE when b > a.
Are you knocking down straw men intentionally, or just need some coffee?
In meantime, I am keeping CircleFill in my tool box...STATIC
Based on the outline/pixels issue, I agree with this. Do you mind posting your freshest copy of the function? Be sure to nerf it down to handle just circles, which I imagine render without boobs.
I swear I wanted to lay this thing to rest like 5 pages ago... Are you saying the so-called gold standard function overlaps itself at the cardinal points 0, pi/2, pi, 3pi/2? Wouldn't that make it bronze or worse?
I swear I wanted to lay this thing to rest like 5 pages ago...
Circle is easy to find, complicated to work on. Just open libqb.cpp and search “circle”— it’s the first result I found. (Sub__circle, or something similar, is the actual name.)
bplus is right about the inherent CIRCLE command (with eccentricity) not perfectly agreeing without our results. The difference is SO minuscule that our algorithms should probably not change though.
bplus is right about the inherent CIRCLE command (with eccentricity) not perfectly agreeing without our results. The difference is SO minuscule that our algorithms should probably not change though.
https://www.qb64.org/forum/index.php?topic=287.msg1806#msg1806 (https://www.qb64.org/forum/index.php?topic=287.msg1806#msg1806)
want to know why?
I ain't religious but "Dammit Allah", said Mohamed :-(
Am I gonna be killed by assassin for depicting the prophet like that? (I'll be waiting for you.)
So this means CIRCLE has a bug. We should start a new thread for that where it belongs if nobody has yet.
Don't think anyone is going to mess with CIRCLE to fix it, it is an extremely rare case where the overlap bug enters awareness. Look how long it took me to run across it. Just file it under weird things about CIRCLE like the problem with arcs and PAINTING pie slices.
Alrighty, considering using this for the final submission. Super bare-bones as it should be (whoever wants some backstory will be able to click a link to this thread). The obvious contributors are, in ABC order, bplus, pete, smcneill, and yours truly. Anyone not in favor, speak now or forever hold your peace. (I'm interested in moving on to the next thing, as is probably everyone.)
I made an effort to unify the notation, so if you *do* have an edit to make, use what's posted below, or make sure the notation is maintained.
EDIT
Opps, didn't add the un-filled, yes-tilted ellipse yet. Luckily this is so easy even *I* can do that, as it won't be needing any newfangled underscore technology. Just my original post without the PAINT statement.Code: QB64: [Select]
' CX = center x coordinate ' CY = center y coordinate ' R = radius ' C = fill color RadiusError = -Radius X = Radius Y = 0 WHILE X > Y RadiusError = RadiusError + Y * 2 + 1 X = X - 1 RadiusError = RadiusError - X * 2 Y = Y + 1 ' CX = center x coordinate ' CY = center y coordinate ' a = semimajor axis ' b = semiminor axis ' C = fill color w2 = a * a h2 = b * b h2w2 = h2 * w2 y = y + 1 ' destHandle& = destination handle ' CX = center x coordinate ' CY = center y coordinate ' a = semimajor axis ' b = semiminor axis ' ang = clockwise orientation of semimajor axis in radians (0 default) ' C = fill color mx2 = max + max _DEST tef& _SOURCE tef& lasti = i: lastj = j x = 0 x = x + 1 xleft(y) = x x = x + 1 x = x + 1 _DEST destHandle& _FREEIMAGE tef&
Opps, didn't add the un-filled, yes-tilted ellipse yet. Luckily this is so easy even *I* can do that, as it won't be needing any newfangled underscore technology. Just my original post without the PAINT statement.