QB64.org Forum

Active Forums => Programs => Topic started by: STxAxTIC on February 06, 2019, 06:46:38 pm

Title: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 06, 2019, 06:46:38 pm
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]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2.  
  3. CALL efill(50, 150, 80, 40, _RGBA(100, 200, 0, 100))
  4. CALL efill(70, 130, 80, 40, _RGBA(200, 100, 0, 100))
  5.  
  6. SUB efill (x0, y0, a, b, c AS LONG)
  7.     a2 = a / SQR(2)
  8.     b2 = b / SQR(2)
  9.     LINE (-a2 + _WIDTH / 2 + x0, -b2 + _HEIGHT / 2 - y0)-(a2 + _WIDTH / 2 + x0, b2 + _HEIGHT / 2 - y0), c, BF
  10.     LINE (0 + _WIDTH / 2 + x0, -b + _HEIGHT / 2 - y0)-(0 + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  11.     LINE (0 + _WIDTH / 2 + x0, b + _HEIGHT / 2 - y0)-(0 + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0), c
  12.     LINE (-a + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0), c
  13.     LINE (a + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0), c
  14.     FOR i = 1 TO a2
  15.         y1 = b * SQR(1 - i ^ 2 / a ^ 2)
  16.         LINE (i + _WIDTH / 2 + x0, -y1 + _HEIGHT / 2 - y0)-(i + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  17.         LINE (-i + _WIDTH / 2 + x0, -y1 + _HEIGHT / 2 - y0)-(-i + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  18.         LINE (i + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0)-(i + _WIDTH / 2 + x0, y1 + _HEIGHT / 2 - y0), c
  19.         LINE (-i + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0)-(-i + _WIDTH / 2 + x0, y1 + _HEIGHT / 2 - y0), c
  20.     NEXT
  21.     FOR j = 1 TO b2
  22.         x1 = a * SQR(1 - j ^ 2 / b ^ 2)
  23.         LINE (-x1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0), c
  24.         LINE (-x1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0), c
  25.         LINE (x1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0), c
  26.         LINE (x1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0), c
  27.     NEXT

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...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 06, 2019, 08:43:39 pm
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]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2.  
  3. CALL efill(50, 150, 80, 40, _RGBA(100, 200, 0, 100))
  4. CALL efill(70, 130, 80, 40, _RGBA(200, 100, 0, 100))
  5.  
  6. SUB efill (x0, y0, a, b, c AS LONG)
  7.     a2 = a / SQR(2)
  8.     b2 = b / SQR(2)
  9.     LINE (-a2 + _WIDTH / 2 + x0, -b2 + _HEIGHT / 2 - y0)-(a2 + _WIDTH / 2 + x0, b2 + _HEIGHT / 2 - y0), c, BF
  10.     LINE (0 + _WIDTH / 2 + x0, -b + _HEIGHT / 2 - y0)-(0 + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  11.     LINE (0 + _WIDTH / 2 + x0, b + _HEIGHT / 2 - y0)-(0 + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0), c
  12.     LINE (-a + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0), c
  13.     LINE (a + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0), c
  14.     FOR i = 1 TO a2
  15.         y1 = b * SQR(1 - i ^ 2 / a ^ 2)
  16.         LINE (i + _WIDTH / 2 + x0, -y1 + _HEIGHT / 2 - y0)-(i + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  17.         LINE (-i + _WIDTH / 2 + x0, -y1 + _HEIGHT / 2 - y0)-(-i + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  18.         LINE (i + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0)-(i + _WIDTH / 2 + x0, y1 + _HEIGHT / 2 - y0), c
  19.         LINE (-i + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0)-(-i + _WIDTH / 2 + x0, y1 + _HEIGHT / 2 - y0), c
  20.     NEXT
  21.     FOR j = 1 TO b2
  22.         x1 = a * SQR(1 - j ^ 2 / b ^ 2)
  23.         LINE (-x1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0), c
  24.         LINE (-x1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0), c
  25.         LINE (x1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0), c
  26.         LINE (x1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0), c
  27.     NEXT

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...

Preliminary test question because the ellipse is not drawing where I think it should:
Why isn't your ellipse origin at x0, y0?
What are all the _WIDTH and _HEIGHT functions (constants?) doing in the code?
Can I assume a is the x radius and b the y radius?
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2.  
  3.  
  4. CALL efill(50, 150, 80, 40, _RGBA(100, 200, 0, 100))
  5. CALL efill(70, 130, 80, 40, _RGBA(200, 100, 0, 100))
  6. CIRCLE (50, 150), 80, _RGB(255, 255, 255)
  7.  
  8. SUB efill (x0, y0, a, b, c AS LONG)
  9.     a2 = a / SQR(2)
  10.     b2 = b / SQR(2)
  11.     LINE (-a2 + _WIDTH / 2 + x0, -b2 + _HEIGHT / 2 - y0)-(a2 + _WIDTH / 2 + x0, b2 + _HEIGHT / 2 - y0), c, BF
  12.     LINE (0 + _WIDTH / 2 + x0, -b + _HEIGHT / 2 - y0)-(0 + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  13.     LINE (0 + _WIDTH / 2 + x0, b + _HEIGHT / 2 - y0)-(0 + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0), c
  14.     LINE (-a + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0), c
  15.     LINE (a + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, 0 + _HEIGHT / 2 - y0), c
  16.     FOR i = 1 TO a2
  17.         y1 = b * SQR(1 - i ^ 2 / a ^ 2)
  18.         LINE (i + _WIDTH / 2 + x0, -y1 + _HEIGHT / 2 - y0)-(i + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  19.         LINE (-i + _WIDTH / 2 + x0, -y1 + _HEIGHT / 2 - y0)-(-i + _WIDTH / 2 + x0, -b2 - 1 + _HEIGHT / 2 - y0), c
  20.         LINE (i + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0)-(i + _WIDTH / 2 + x0, y1 + _HEIGHT / 2 - y0), c
  21.         LINE (-i + _WIDTH / 2 + x0, b2 + 1 + _HEIGHT / 2 - y0)-(-i + _WIDTH / 2 + x0, y1 + _HEIGHT / 2 - y0), c
  22.     NEXT
  23.     FOR j = 1 TO b2
  24.         x1 = a * SQR(1 - j ^ 2 / b ^ 2)
  25.         LINE (-x1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0), c
  26.         LINE (-x1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0)-(-a2 - 1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0), c
  27.         LINE (x1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, j + _HEIGHT / 2 - y0), c
  28.         LINE (x1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0)-(a2 + 1 + _WIDTH / 2 + x0, -j + _HEIGHT / 2 - y0), c
  29.     NEXT
  30.  
  31.  

As it stands I can not compare because it's not drawing where it should. Also I am seeing a line overlap in the EllipseFill test (Steve's).
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 06, 2019, 09:21:25 pm
I put the origin in the center of screen and use normal Cartesian coordinates. The conversion does probably confound a speed test, so you have a point.

Steve's is gonna be faster - I finally did a web search on this and found what I sortof expected. You need to avoid square roots and trig when doing this stuff. Not sure where the inspiration where his code came from, but it likely won't be beat.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 06, 2019, 09:40:30 pm
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.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 06, 2019, 11:25:10 pm
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.

As I mentioned when I shared it, I’m not 100% certain where my EllipseFill came from.  It was in an old untitled.bas file on my drive from SDL days, with a date-stamp years old.  I honestly don’t remember if I derived it from the CircleFill, or if it came from somewhere else.

I’m thinking it was probably inspired/derived from McIlroy's Ellipse Algorithm, or L. Patrick‘s work, but I won’t swear to anything.  Link here to read up on it a bit:  http://enchantia.com/graphapp/doc/tech/ellipses.html  The medication the quacks have me on for my heart fuddle my long-term memory and make it rather difficult for me to remember all the finer points of things, and I truly can’t say where EllipseFill floated into my possession from now.

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.  ;)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 06, 2019, 11:55:25 pm
Here is an update of EllipseFill versus CircleFill, they run neck and neck on 10000 large fills.
Code: QB64: [Select]
  1. _TITLE "Steves EllipseFill (right) vrs gold standard CircleFill (left), 2 tests take about 17 secs each after you press enter."
  2.  
  3. DEFINT A-Z
  4. SCREEN _NEWIMAGE(1220, 680, 32)
  5. _SCREENMOVE 100, 20
  6.  
  7. EllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  8. EllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  9. INPUT "EllipseFill (fel) overlap test, press enter to continue "; wate$
  10. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  11. start## = TIMER
  12. FOR i = 1 TO 10000
  13.     EllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 100)
  14. EllipseTime## = TIMER - start##
  15. _PRINTSTRING (800, 615), "Time for 10000 EllipseFills:" + STR$(EllipseTime##)
  16.  
  17.  
  18. ' ==================================================== compare to the old gold standard
  19.  
  20. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  21. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  22. LOCATE 1, 1: INPUT "CircleFill overlap test, press enter to continue "; wate$
  23. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  24.  
  25. start## = TIMER
  26. FOR i = 1 TO 10000
  27.     CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 100)
  28. OldCircleTime## = TIMER - start##
  29. _PRINTSTRING (200, 615), "Time for 10000 Circle Fills:" + STR$(OldCircleTime##)
  30.  
  31. 'old circle fill
  32. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  33.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  34.     DIM X AS INTEGER, Y AS INTEGER
  35.  
  36.     Radius = ABS(R)
  37.     RadiusError = -Radius
  38.     X = Radius
  39.     Y = 0
  40.  
  41.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  42.  
  43.     ' Draw the middle span here so we don't draw it twice in the main loop,
  44.     ' which would be a problem with blending turned on.
  45.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  46.  
  47.     WHILE X > Y
  48.         RadiusError = RadiusError + Y * 2 + 1
  49.         IF RadiusError >= 0 THEN
  50.             IF X <> Y + 1 THEN
  51.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  52.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  53.             END IF
  54.             X = X - 1
  55.             RadiusError = RadiusError - X * 2
  56.         END IF
  57.         Y = Y + 1
  58.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  59.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  60.     WEND
  61.  
  62.  
  63. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  64.     DIM a AS LONG, b AS LONG
  65.     DIM x AS LONG, y AS LONG
  66.     DIM xx AS LONG, yy AS LONG
  67.     DIM sx AS LONG, sy AS LONG
  68.     DIM e AS LONG
  69.  
  70.     a = 2 * rx * rx
  71.     b = 2 * ry * ry
  72.     x = rx
  73.     xx = ry * ry * (1 - rx - rx)
  74.     yy = rx * rx
  75.     sx = b * rx
  76.  
  77.     DO WHILE sx >= sy
  78.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  79.         IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  80.  
  81.         y = y + 1
  82.         sy = sy + a
  83.         e = e + yy
  84.         yy = yy + a
  85.  
  86.         IF (e + e + xx) > 0 THEN
  87.             x = x - 1
  88.             sx = sx - b
  89.             e = e + xx
  90.             xx = xx + b
  91.         END IF
  92.     LOOP
  93.  
  94.     x = 0
  95.     y = ry
  96.     xx = rx * ry
  97.     yy = rx * rx * (1 - ry - ry)
  98.     e = 0
  99.     sx = 1
  100.     sy = a * ry
  101.  
  102.     DO WHILE sx <= sy
  103.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  104.         LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  105.  
  106.         DO
  107.             x = x + 1
  108.             sx = sx + b
  109.             e = e + xx
  110.             xx = xx + b
  111.         LOOP UNTIL (e + e + yy) > 0
  112.  
  113.         y = y - 1
  114.         sy = sy - a
  115.         e = e + yy
  116.         yy = yy + a
  117.  
  118.     LOOP
  119.  
  120.  
  121.  

Oddly Static's code was NOT doing that badly, I am not sure why, I just couldn't draw the darn thing where I wanted to really check if I had it setup correctly. If you draw half a 300 radius circle off screen would that cut the time in half?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 07, 2019, 07:46:17 am
Cool bplus, thanks for doing the legwork on this. Really appreciate it.

The reason I opened this thread in this way was to harvest our first bit of content for an upcoming new section on these forums. (This will be formally "announced" later.) The new section will be like Samples Lite: not quite full-fledged demos, but instead we will collect functions and libraries that do one thing extremely well without the user having to learn anything about the code. A pure collection of black boxes, if possible.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: _vince on February 08, 2019, 01:24:09 pm
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]
  1.         IF (e + e + xx) > 0 THEN
  2.     yy = rx * rx * (1 - ry - ry)
  3.  

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?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 08, 2019, 03:20:10 pm
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]
  1.         IF (e + e + xx) > 0 THEN
  2.     yy = rx * rx * (1 - ry - ry)
  3.  

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?

Run a speed test sometime and compare speed of operations.

x * x is faster than x ^ 2.
x + x is faster than 2 * x.
-x is MUCH faster than -1 * x.  (Negation vs negative multiplication)

UnseenMachine and I used to have a topic over at [abandoned, outdated and now likely malicious qb64 dot net website - don’t go there] which discussed operational optimization techniques, but unfortunately, .net seems to be forever lost to time now.

A few other pointers, off the top of my head: 
DO.. LOOP is faster than FOR...NEXT.

Assignment to an integer variable is faster than INT.   (DIM x AS INTEGER: x = 3.2 is faster than x! = INT(3.2)

Try to limit REDIM _PRESERVE calls as much as possible.

Instead of:
DO
   count = count + 1
   REDIM _PRESERVE Array(UBOUND(Array) + 1)
   ‘do stuff
LOOP

Do:
REDIM _PRESERVE Array(UBOUND(Array) + 10000)
DO
    count = count + 1
    IF count > UBOUND(Array) THEN REDIM _PRESERVE Array(UBOUND(Array) + 10000)
    ‘Do stuff
LOOP
   REDIM _PRESERVE ARRAY(count) ‘remove unneeded Array space..



Just lots of little things like these throughout years of time testing and experience, are what I use to optimize performance.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 09, 2019, 06:39:23 pm
Alright, here are two functions that draw filled tilted ellipses. One suffers from a serious aliasing problem due to drawing diagonal lines. I wonder if (i) all languages would do this, or (ii) it's something in opengl, (iii) it's not opengl inherently, but Galleon's effort to make graphics modes compatible with old behavior (this is prolly it). The second function cheats using PAINT. Anyway, have a ball.

Code: QB64: [Select]
  1.  
  2. DIM SHARED CenterX
  3. DIM SHARED CenterY
  4. CenterX = _WIDTH / 2
  5. CenterY = _HEIGHT / 2
  6.  
  7. FOR k = 0 TO 3.14 * 2 + .01 STEP .01
  8.     CLS
  9.     CALL TiltedEllipseFill1(100, 100, 100, 60, k)
  10.     CALL TiltedEllipseFill2(-100, -100, 100, 60, k)
  11.     _LIMIT 20
  12.     _DISPLAY
  13.  
  14.  
  15. SUB TiltedEllipseFill1 (x0, y0, a, b, ang)
  16.     FOR i = -a TO a
  17.         yy = b * SQR(1 - i ^ 2 / a ^ 2)
  18.         x1 = i
  19.         x2 = i
  20.         y1 = yy
  21.         y2 = -yy
  22.         x1i = x1
  23.         x2i = x2
  24.         y1i = y1
  25.         y2i = y2
  26.         x1 = (x1i) * COS(ang) - (y1i) * SIN(ang)
  27.         y1 = (x1i) * SIN(ang) + (y1i) * COS(ang)
  28.         x2 = (x2i) * COS(ang) - (y2i) * SIN(ang)
  29.         y2 = (x2i) * SIN(ang) + (y2i) * COS(ang)
  30.         x1 = x1 + x0 + CenterX
  31.         x2 = x2 + x0 + CenterX
  32.         y1 = -y1 - y0 + CenterY
  33.         y2 = -y2 - y0 + CenterY
  34.         LINE (x1, y1)-(x2, y2), 4
  35.     NEXT
  36.  
  37. SUB TiltedEllipseFill2 (x0, y0, a, b, ang)
  38.     FOR k = 0 TO 2 * 3.14 + .1 STEP .1
  39.         i = a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  40.         j = -a * COS(k) * SIN(ang) + b * SIN(k) * COS(ang)
  41.         i = i + x0 + CenterX
  42.         j = -j - y0 + CenterY
  43.         IF k <> 0 THEN
  44.             LINE -(i, j), 5
  45.         ELSE
  46.             PSET (i, j), 5
  47.         END IF
  48.     NEXT
  49.     PAINT (x0 + CenterX, -y0 + CenterY), 5, 5
  50.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 09, 2019, 07:25:28 pm
Hey STATIC,

Kudos for being first with code for tilted ellipse.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 09, 2019, 08:05:53 pm
Thanks bplus!

I think in practice, the second function (Without the alias problem) will be the keeper. Since it relies on PAINT for filling, it has to be its own image or whatever if we want to place it over other shapes, of course.

Just so it's all in one place, here is the derivation of the equations in the second function. Vectors are in bold.

(1)
Recall that an un-tilted ellipse with major and minor axes a, b, respectively, centered at the point (0, 0) can be represented by a vector r0 and an angular parameter q, namely

r0 = i a cos(q) + j b sin (q) ,

where unit vectors i = (1, 0) and j = (0, 1) align with the horizontal and vertical directions, respectively.

(As a quick aside, it's trivial to eliminate the parameter q in the above to arrive at (x/a)^2 + (y/b)^2 = 1.)

(2)
It must follow that a tilted ellipse aligns with a different pair of unit vectors u and v in place of i and j. Whatever u and v are, the tilted ellipse obeys:

r = u a cos(q) + v b sin (q)

(3)
The next task is to determine u and v in terms of i and j. For i and j to "swing into" u and v across angle w, we apply a rotation matrix as follows:

u = i cos(w) - j sin(w)
v = i sin(w) + j cos(w)

(4)
Plugging the new equations for u and v into r, we find:

r = (i cos(w) - j sin(w)) a cos(q) + (i sin(w) + j cos(w)) b sin(q)

r = i (a cos(q) cos(w) + b sin (q) sin(w)) + j (-a cos(q)sin(w) + b sin(q) sin(w))

(5)
Isolate the i and j components to finally land at equations for x and y

x = a cos(q) cos(w) + b sin (q) sin(w)
y = -a cos(q)sin(w) + b sin(q) sin(w)


... and these are precisely what are implemented in the code (which uses slightly different notation)

Code: QB64: [Select]
  1. ... = a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  2. ... = -a * COS(k) * SIN(ang) + b * SIN(k) * COS(ang)
  3.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 09, 2019, 08:16:33 pm
And as I learned early on in QB64 forum, you can draw your ellipse in an isolated _DEST and transfer the image to wherever needed without concern of PAINT running into other objects. (Yeah, you said that ;-)) ) Problem is, PAINT is slow for circle filling.

I still think we need a sub that is not dependent upon knowing where the center of the screen is.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 09, 2019, 08:21:43 pm
I figured PAINT would be slow... but then again it needs four trig calls, so it was never destined to be lightning. One possible avenue that remains is to do a similar analysis that led to Steve's code, and then generalize it for tilted shapes. I see this going nowhere unfortunately, simply because (i) you might have to draw diagonals and suffer the same alias problem as my first method, and then (ii) I haven't been able to attain a parameter-free expression for the ellipse that is strictly an XY equation. Not that it's *required*, but would be very hand for making a fast function. I truly doubt such an equation exists after a few hours of mucking around in equation-land.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 09, 2019, 09:35:28 pm
I have modified the tiltedEllispeFill2 sub to be used without needing the center of screen and setup in a separate destination and transferred to destHandle& with _PUTIMAGE.

Another problem with PAINT is that it does not do Alpha (at least as a boundry).
Another problem with PAINT is very narrow ellipse:
Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse test"
  2. SCREEN _NEWIMAGE(800, 600, 32)
  3. clr = _RGB32(255, 128, 64)
  4. TiltedEllipseFill2 0, 400, 300, 300, 200, _PI(1 / 4), clr
  5. CIRCLE (400, 300), 300
  6. CIRCLE (400, 300), 200
  7. INPUT "Hopefully the ellipse radii fits in both circles, press enter..."; wate$
  8. WHILE _KEYDOWN(27) = 0
  9.     TiltedEllipseFill2 0, RND * 600 + 100, RND * 400 + 100, RND * 100 + 1, RND * 100 + 1, _PI(RND * 2), _RGB32(RND * 255, RND * 255, RND * 255)
  10.     _DISPLAY
  11.     _LIMIT 10
  12.  
  13. SUB TiltedEllipseFill2 (destHandle&, x0, y0, a, b, ang, c AS _UNSIGNED LONG)
  14.     IF a > b THEN max = a + 1 ELSE max = b + 1
  15.     tef& = _NEWIMAGE(2 * max, 2 * max)
  16.     _DEST tef&
  17.     FOR k = 0 TO 2 * 3.14 + .1 STEP .1
  18.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  19.         j = max - a * COS(k) * SIN(ang) + b * SIN(k) * COS(ang)
  20.         IF k <> 0 THEN
  21.             LINE (lasti, lastj)-(i, j), c
  22.         ELSE
  23.             PSET (i, j), c
  24.         END IF
  25.         lasti = i: lastj = j
  26.     NEXT
  27.     PAINT (max, max), c
  28.     _PUTIMAGE (x0 - max, y0 - max)-STEP(2 * max, 2 * max), tef&, destHamdle&
  29.     _FREEIMAGE tef&
  30.  

 
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 09, 2019, 09:50:36 pm
There's always an edge case I guess.

Welp, it turns out that the off-circle-ness is called the eccentricity, given by e=sqrt(1-b^2/a^2), where circles have e=0. In practice with this function, the programmer should rethink what he's doing if looking to apply this function to very eccentric shapes that are fussy down to the pixel.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 09, 2019, 09:58:54 pm
... With all of the above said, do we all agree that:

(i) The code Steve brought to the table is the best flat ellipse fill
(ii) Bplus's mod to my tilted ellipse thing is basically ready to ship.

If that's true, then we have the first trickle of entries for a new subforum. Any last minute thoughts on these?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 09, 2019, 11:06:07 pm
Hold on, I am not ready to ship, I found a solution to alpha, still checking results.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 09, 2019, 11:19:15 pm
No PAINT, no _PUTIMAGE, using rectilinear lines with BF! Now have alpha AND perfect narrow ellipse fills.
Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse test" ' B+ 2019-02-09 Thanks to STxAxTIC's formula's
  2. SCREEN _NEWIMAGE(800, 600, 32)
  3. _SCREENMOVE 200, 40
  4. clr = _RGBA32(255, 128, 30, 50)
  5. TiltedEllipseFill 0, 400, 300, 300, 200, _PI(1 / 4), clr
  6. CIRCLE (400, 300), 300
  7. CIRCLE (400, 300), 200
  8. INPUT "Hopefully the ellipse radii fits in both circles, press enter..."; wate$
  9. WHILE _KEYDOWN(27) = 0
  10.     TiltedEllipseFill 0, RND * 600 + 100, RND * 400 + 100, RND * 100 + 1, RND * 100 + 1, _PI(RND * 2), _RGBA32(RND * 255, RND * 255, RND * 255, RND * 255)
  11.     _DISPLAY
  12.     _LIMIT 10
  13.  
  14. SUB TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c AS _UNSIGNED LONG)
  15.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  16.     DIM prc AS _UNSIGNED LONG
  17.     prc = _RGB32(255, 255, 255, 255)  ' prc for Paint Readable Color
  18.     IF a > b THEN max = a + 1 ELSE max = b + 1
  19.     mx2 = max + max
  20.     tef& = _NEWIMAGE(mx2, mx2)
  21.     _DEST tef&
  22.     _SOURCE tef& 'point wont read without this!
  23.     FOR k = 0 TO 6.2832 + .05 STEP .1
  24.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  25.         j = max - a * COS(k) * SIN(ang) + b * SIN(k) * COS(ang)
  26.         IF k <> 0 THEN
  27.             LINE (lasti, lastj)-(i, j), prc
  28.         ELSE
  29.             PSET (i, j), prc
  30.         END IF
  31.         lasti = i: lastj = j
  32.     NEXT
  33.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  34.     FOR y = 0 TO mx2
  35.         x = 0
  36.         WHILE POINT(x, y) <> prc AND x < mx2
  37.             x = x + 1
  38.         WEND
  39.         xleft(y) = x
  40.         WHILE POINT(x, y) = prc AND x < mx2
  41.             x = x + 1
  42.         WEND
  43.         WHILE POINT(x, y) <> prc AND x < mx2
  44.             x = x + 1
  45.         WEND
  46.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  47.     NEXT
  48.     _DEST destHandle&
  49.     FOR y = 0 TO mx2
  50.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  51.     NEXT
  52.     _FREEIMAGE tef&
  53.  

 
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 09, 2019, 11:22:50 pm
Nice work guys! For non-SCREEN 0 stuff, that is. ;)

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 09, 2019, 11:28:58 pm
Hehe, leave it to Pete to beat me to the first comment. Thanks for following this!

Absolutely lovely work bplus. I'm shocked the whole thing came together so quickly.

As everyone probably noticed, these efforts will wind up in a place of their own, so that anytime these questions come up again, we have the answer in a nice section without a flame war occurring underneath. (My own fault usually.)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 09, 2019, 11:49:52 pm
Paint can handle alpha if _DONTBLEND is in use.  If you’re blending alpha, draw to a separate image first, then _PUTIMAGE the finished ellipseto the main screen.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 09, 2019, 11:55:01 pm
Found two small things that only help:

Code: QB64: [Select]
  1. FOR k = 0 TO 6.2832 + .05 STEP .05

The small offset next to the factor of 2*pi should agree with the step size.

And more interestingly:

Code: QB64: [Select]
  1. IF xleft(y) <> mx2 THEN LINE (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c

... doesn't need BF or even B. Every line is strictly horizontal as y + y0 - max is the only y-argument in the LINE statement above.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 10, 2019, 12:00:30 am
And since the function has broken the underscore barrier, so to speak - what about what Steve just said? Can that make the whole thing smaller and faster?

Damn, while I love my armchair over here in the Science department, I should mingle more with the engineers who use QB64 commands a little more often...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 12:15:12 am
Well I found another correction, the angle and equations work for a Cartesian coordinate system but unfortunately Basic angles start 0 due east and rotate clockwise, so I adjusted equations to follow Basic Angle system.

BF used for lines because according to Steve it is faster than drawing a line. It was a part of the optimizations for CircleFill.

I rounded pi * 2 up so .05 would have worked with .1 STEP (it was) but I did forget I changed back to .1 with STEP. That, BTW is another place that could be optimized for best size to step depending on big or small ellipse circumference.

Here is TiltedEllipseFill with QB64 Basic System of Angle designations:
Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse Oops" ' B+ 2019-02-10 oops we have a problem with Angle designation
  2. ' Thanks to STxAxTIC's formula's
  3.  
  4. ' Oops! I forgot to take into account STxAxTIC's Cartisian Coordinate System: Angles
  5.  
  6. SCREEN _NEWIMAGE(800, 600, 32)
  7. _SCREENMOVE 200, 40
  8. clr = _RGBA32(255, 128, 30, 50)
  9. WHILE _KEYDOWN(27) = 0
  10.     CLS
  11.     a = a + _PI(1 / 180)
  12.     PRINT "Angle:"; INT(_R2D(a))
  13.     TiltedEllipseFill 0, 400, 300, 300, 200, a, clr
  14.     LINE (400, 300)-(400 + 300 * COS(a), 300 + 300 * SIN(a))
  15.     _DISPLAY
  16.     _LIMIT 10
  17.  
  18. SUB TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c AS _UNSIGNED LONG)
  19.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  20.     DIM prc AS _UNSIGNED LONG
  21.     prc = _RGB32(255, 255, 255, 255)
  22.     IF a > b THEN max = a + 1 ELSE max = b + 1
  23.     mx2 = max + max
  24.     tef& = _NEWIMAGE(mx2, mx2)
  25.     _DEST tef&
  26.     _SOURCE tef& 'point wont read without this!
  27.     FOR k = 0 TO 6.2832 + .05 STEP .1
  28.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  29.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  30.         IF k <> 0 THEN
  31.             LINE (lasti, lastj)-(i, j), prc
  32.         ELSE
  33.             PSET (i, j), prc
  34.         END IF
  35.         lasti = i: lastj = j
  36.     NEXT
  37.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  38.     FOR y = 0 TO mx2
  39.         x = 0
  40.         WHILE POINT(x, y) <> prc AND x < mx2
  41.             x = x + 1
  42.         WEND
  43.         xleft(y) = x
  44.         WHILE POINT(x, y) = prc AND x < mx2
  45.             x = x + 1
  46.         WEND
  47.         WHILE POINT(x, y) <> prc AND x < mx2
  48.             x = x + 1
  49.         WEND
  50.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  51.     NEXT
  52.     _DEST destHandle&
  53.     FOR y = 0 TO mx2
  54.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  55.     NEXT
  56.     _FREEIMAGE tef&
  57.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 12:23:36 am
The _DONTBLEND might fix the paint issue but not the poor painting job done with narrow ellipsii.

It's timed tests time if Steve is correct.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 10, 2019, 12:27:23 am
Again your thoroughness is appreciated. Once this thread cools down we'll crystallize the results in the new section. In the meantime, anyone with works that may fit there - sorting routines and the like - are welcome to post that stuff to Programs, or bump it to resurrect the thread.

(That reminds me - Steve, is your screen capture stuff hanging around? We could use a bump on that one, plus a handful of your other things that I'll try to name if they don't surface naturally soon.)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 12:43:07 am
For me, _DONTBLEND makes everything Opaque so whole image rectangle (yuck!!), black and all, is transferred over with _PUTIMAGE, with no alpha transparencies.

Steve may have solution?

Meanwhile a timed test with the alpha beauties.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 11:53:18 am
Problem!

While doing speed tests, I found Steve's EllipseFill was drawing overlapping lines at regular intervals with a held at 400 and b increased from 0 to 400.

Overlaps at b=45, 57, 67, 81, 86, 93... that is just the first few found.
Code: QB64: [Select]
  1. _TITLE "Ellipsefill from Steve"
  2. SCREEN _NEWIMAGE(1000, 700, 32)
  3. _SCREENMOVE 180, 20
  4. 'B+ 2019-02-10 resave this code to
  5. 'just test this code for proper filling without overlap, timed tests are else where
  6.  
  7. FOR i = 0 TO 400 'draw ellipse at various heights
  8.  
  9.     CLS
  10.     PRINT "b Radius"; i; "   press any to get to 400, <backspace> to go back one, <esc> for next test."
  11.  
  12.     EllipseFill 500, 350, 400, i, _RGBA(255, 255, 255, 40)
  13.     k$ = ""
  14.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  15.     IF k$ = CHR$(8) THEN i = i - 2
  16.     IF k$ = CHR$(27) THEN EXIT FOR
  17.  
  18. WHILE _KEYDOWN(32) = 0 'check all sorts random stuff
  19.     EllipseFill RND * 1000, RND * 700, RND * 100, RND * 100, _RGBA32(255 * RND, 255 * RND, 255 * RND, 100 * RND)
  20.     _LIMIT 1
  21.  
  22.  
  23.  
  24. ' with Steve's EllipseFill, who needs CircleFill? fix for 0 radii 2019-02-05
  25. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  26. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  27. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  28.     DIM a AS LONG, b AS LONG
  29.     DIM x AS LONG, y AS LONG
  30.     DIM xx AS LONG, yy AS LONG
  31.     DIM sx AS LONG, sy AS LONG
  32.     DIM e AS LONG
  33.  
  34.     IF rx = 0 OR ry = 0 THEN EXIT SUB 'nothing to draw, B+ added this to avoid errors when b was 0
  35.  
  36.     a = 2 * rx * rx
  37.     b = 2 * ry * ry
  38.     x = rx
  39.     xx = ry * ry * (1 - rx - rx)
  40.     yy = rx * rx
  41.     sx = b * rx
  42.  
  43.     DO WHILE sx >= sy 'no = ? , nope that didn't help
  44.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  45.         IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  46.  
  47.         y = y + 1
  48.         sy = sy + a
  49.         e = e + yy
  50.         yy = yy + a
  51.  
  52.         IF (e + e + xx) > 0 THEN 'add = ? nope no fix
  53.             x = x - 1
  54.             sx = sx - b
  55.             e = e + xx
  56.             xx = xx + b
  57.         END IF
  58.     LOOP
  59.  
  60.     x = 0
  61.     y = ry
  62.     xx = rx * ry
  63.     yy = rx * rx * (1 - ry - ry)
  64.     e = 0
  65.     sx = 0
  66.     sy = a * ry
  67.  
  68.     DO WHILE sx <= sy ' no  =  ? fixed once but mostly no fix
  69.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  70.         LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  71.  
  72.         DO
  73.             x = x + 1
  74.             sx = sx + b
  75.             e = e + xx
  76.             xx = xx + b
  77.         LOOP UNTIL (e + e + yy) > 0 'add = ? nope no fix
  78.  
  79.         y = y - 1
  80.         sy = sy - a
  81.         e = e + yy
  82.         yy = yy + a
  83.  
  84.     LOOP
  85.  
  86.  
  87.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 10, 2019, 11:59:36 am
Your attention to detail is indispensable plus! I wonder if 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...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 12:01:16 pm
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...


Probably I am starting to become PIA.

I am next going to submit CircleFill to same test.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 12:18:28 pm
Don't give up. I don't know a single person who gets a program to run correctly from the first time out of the gate, unless it's that Hello World guru.

I don't see an obvious pattern in the results you posted, which means something in the algorithm is crunching numbers with probably some decimal off in the wrong direction.

BTW- you probably meant PITA, instead of PIA, you PITA!

Pete :D
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 12:22:22 pm
Well hurray, CircleFill still holds up!
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 03:26:53 pm
Here's my fix to the 1 to 400 problem. Hey, check it carefully, as I flipped through it fast. No patience for this crap, sorry.

Anyway, if it works it works because it simply checks the boundaries set byt the fist line statements and doesn't let the second set of line statements overlap them, which was causing the initial problem at radius entries like 45, 67, etc.

Code: QB64: [Select]
  1. _TITLE "Ellipsefill from Steve"
  2. SCREEN _NEWIMAGE(1000, 700, 32)
  3. _SCREENMOVE 180, 20
  4. 'B+ 2019-02-10 resave this code to
  5. 'just test this code for proper filling without overlap, timed tests are else where
  6.  
  7. FOR i = 1 TO 400 'draw ellipse at various heights
  8.     CLS
  9.     PRINT "b Radius"; i; " Press any to get to 400, <backspace> to go back one, <esc> for next test."
  10.     EllipseFill 500, 350, 400, i, _RGBA(255, 255, 255, 40)
  11.     k$ = ""
  12.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  13.     IF k$ = CHR$(8) THEN i = i - 2
  14.     IF k$ = CHR$(27) THEN EXIT FOR
  15.  
  16. WHILE _KEYDOWN(32) = 0 'check all sorts random stuff
  17.     EllipseFill RND * 1000, RND * 700, RND * 100, RND * 100, _RGBA32(255 * RND, 255 * RND, 255 * RND, 100 * RND)
  18.     _LIMIT 1
  19.  
  20. ' with Steve's EllipseFill, who needs CircleFill? fix for 0 radii 2019-02-05
  21. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  22. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  23. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  24.  
  25. DIM sx AS LONG, sy AS LONG
  26.  
  27. IF rx = 0 OR ry = 0 THEN EXIT SUB 'nothing to draw, B+ added this to avoid errors when b was 0
  28.  
  29. a = 2 * rx * rx
  30. b = 2 * ry * ry
  31. x = rx
  32. xx = ry * ry * (1 - 2 * rx)
  33. yy = rx * rx
  34. sx = b * rx
  35.  
  36. DO WHILE sx >= sy 'no = ? , nope that didn't help
  37.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  38.     IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  39.     y = y + 1
  40.     sy = sy + a
  41.     e = e + yy
  42.     yy = yy + a
  43.  
  44.     IF (e + e + xx) > 0 THEN 'add = ? nope no fix
  45.         x = x - 1
  46.         sx = sx - b
  47.         e = e + xx
  48.         xx = xx + b
  49.     END IF
  50. oldy = y ' Pete's fix
  51. x = 0
  52. y = ry
  53. xx = rx * ry
  54.  
  55. yy = rx * rx * (1 - 2 * ry)
  56. e = 0
  57. sx = 0
  58. sy = a * ry
  59.  
  60.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  61.     LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  62.     DO
  63.         x = x + 1
  64.         sx = sx + b
  65.         e = e + xx
  66.         xx = xx + b
  67.     LOOP UNTIL (e + e + yy) > 0 'add = ? nope no fix
  68.     y = y - 1
  69.     sy = sy - a
  70.     e = e + yy
  71.     yy = yy + a
  72. LOOP UNTIL y < oldy
  73.  
  74.  
  75.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 03:53:06 pm
Nice Pete! I will run time tests on this fix.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 03:58:18 pm
Hey did you guys find out that different ways of expressing equations are calculated faster? Case in point, I tend to own code, and I started changing things like - r + r to - 2 * r. I was about to change things like ry * ry to ry ^2, but then I thought I'd ask here first. If - r + r, or whatever it was, would run faster than the 2 * r I changed it to, then by all means, change it back before you do the speed tests. That way, you have apples to apples, should it make a difference.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 04:47:51 pm
OK they are still running neck and neck, the gold standard running a very large radius circle 10000 time versus EllipseFill now with latest fix from Pete in a timed test. So the Ellipse fill can be used both for CircleFill and EllipseFill when ellipse needed has axis parallel to x, y axis, otherwise use TiltedEllipseFill for angular Ellipse fills.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 04:51:55 pm
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
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 04:53:37 pm
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

Yes, nothing with the math was changed that I could see.
Here is the test code for time:
Code: QB64: [Select]
  1. _TITLE "Steves EllipseFill (right) vrs gold standard CircleFill (left), 2 tests take about 17 secs each after you press enter."
  2.  
  3. DEFINT A-Z
  4. SCREEN _NEWIMAGE(1220, 680, 32)
  5. _SCREENMOVE 100, 20
  6.  
  7. EllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  8. EllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  9. INPUT "EllipseFill (fel) overlap test, press enter to continue "; wate$
  10. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  11. start## = TIMER
  12. FOR i = 1 TO 10000
  13.     EllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 100)
  14. EllipseTime## = TIMER - start##
  15. _PRINTSTRING (800, 615), "Time for 10000 EllipseFills:" + STR$(EllipseTime##)
  16.  
  17.  
  18. ' ==================================================== compare to the old gold standard
  19.  
  20. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  21. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  22. LOCATE 1, 1: INPUT "CircleFill overlap test, press enter to continue "; wate$
  23. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  24.  
  25. start## = TIMER
  26. FOR i = 1 TO 10000
  27.     CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 100)
  28. OldCircleTime## = TIMER - start##
  29. _PRINTSTRING (200, 615), "Time for 10000 Circle Fills:" + STR$(OldCircleTime##)
  30.  
  31. 'old circle fill
  32. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  33.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  34.     DIM X AS INTEGER, Y AS INTEGER
  35.  
  36.     Radius = ABS(R)
  37.     RadiusError = -Radius
  38.     X = Radius
  39.     Y = 0
  40.  
  41.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  42.  
  43.     ' Draw the middle span here so we don't draw it twice in the main loop,
  44.     ' which would be a problem with blending turned on.
  45.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  46.  
  47.     WHILE X > Y
  48.         RadiusError = RadiusError + Y * 2 + 1
  49.         IF RadiusError >= 0 THEN
  50.             IF X <> Y + 1 THEN
  51.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  52.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  53.             END IF
  54.             X = X - 1
  55.             RadiusError = RadiusError - X * 2
  56.         END IF
  57.         Y = Y + 1
  58.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  59.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  60.     WEND
  61.  
  62.  
  63. ' now with Pete's fix for overlap 2019-02-10
  64. ' with Steve's EllipseFill, who needs CircleFill? fix for 0 radii 2019-02-05
  65. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  66. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  67. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  68.     DIM a AS LONG, b AS LONG
  69.     DIM x AS LONG, y AS LONG
  70.     DIM xx AS LONG, yy AS LONG
  71.     DIM sx AS LONG, sy AS LONG
  72.     DIM e AS LONG
  73.  
  74.     IF rx = 0 OR ry = 0 THEN EXIT SUB 'nothing to draw, B+ added this to avoid errors when b was 0
  75.  
  76.     a = 2 * rx * rx
  77.     b = 2 * ry * ry
  78.     x = rx
  79.     xx = ry * ry * (1 - rx - rx)
  80.     yy = rx * rx
  81.     sx = b * rx
  82.  
  83.     DO WHILE sx >= sy 'no = ? , nope that didn't help
  84.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  85.         IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  86.  
  87.         y = y + 1
  88.         sy = sy + a
  89.         e = e + yy
  90.         yy = yy + a
  91.  
  92.         IF (e + e + xx) > 0 THEN 'add = ? nope no fix
  93.             x = x - 1
  94.             sx = sx - b
  95.             e = e + xx
  96.             xx = xx + b
  97.         END IF
  98.     LOOP
  99.     oldy = y ' Pete's fix
  100.     x = 0
  101.     y = ry
  102.     xx = rx * ry
  103.     yy = rx * rx * (1 - ry - ry)
  104.     e = 0
  105.     sx = 0
  106.     sy = a * ry
  107.  
  108.     DO '   Pete's fix eliminate >   WHILE sx <= sy ' no  =  ? fixed once but mostly no fix
  109.         LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  110.         LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  111.  
  112.         DO
  113.             x = x + 1
  114.             sx = sx + b
  115.             e = e + xx
  116.             xx = xx + b
  117.         LOOP UNTIL (e + e + yy) > 0 'add = ? nope no fix
  118.  
  119.         y = y - 1
  120.         sy = sy - a
  121.         e = e + yy
  122.         yy = yy + a
  123.  
  124.     LOOP UNTIL y < oldy ' pete's fix
  125.  
  126.  
  127.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 05:16:27 pm
No, reread it. I mean I changed a couple of lines from r + r to 2 * r. I'll post this one with all of the changes I can find to condense the math using powers, * 2, etc. Maybe it runs faster one way or the other, but I just like the math better with 2*, ^2, etc. If it makes no speed difference, it doesn't matter how you want to go about posting the finished product. Just know I changed 2 lines in the one you tested and you can change them back, for conformity sake, if you wish. Either way, yes, it produces the exact same math results.

So here is one I completely converted, unless I missed something.

Code: QB64: [Select]
  1. _TITLE "Ellipsefill from Steve"
  2. SCREEN _NEWIMAGE(1000, 700, 32)
  3. _SCREENMOVE 180, 20
  4. ' Pete changed math operations so r * r is now R^2, r + r is 2 * r, etc.
  5. 'B+ 2019-02-10 resave this code to
  6. 'just test this code for proper filling without overlap, timed tests are else where
  7.  
  8. FOR i = 1 TO 400 'draw ellipse at various heights
  9.     CLS
  10.     PRINT "b Radius"; i; " Press any to get to 400, <backspace> to go back one, <esc> for next test."
  11.     EllipseFill 500, 350, 400, i, _RGBA(255, 255, 255, 40)
  12.     k$ = ""
  13.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  14.     IF k$ = CHR$(8) THEN i = i - 2
  15.     IF k$ = CHR$(27) THEN EXIT FOR
  16.  
  17. WHILE _KEYDOWN(32) = 0 'check all sorts random stuff
  18.     EllipseFill RND * 1000, RND * 700, RND * 100, RND * 100, _RGBA32(255 * RND, 255 * RND, 255 * RND, 100 * RND)
  19.     _LIMIT 1
  20.  
  21. ' with Steve's EllipseFill, who needs CircleFill? fix for 0 radii 2019-02-05
  22. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  23. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  24. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  25.  
  26. DIM sx AS LONG, sy AS LONG
  27.  
  28. IF rx = 0 OR ry = 0 THEN EXIT SUB 'nothing to draw, B+ added this to avoid errors when b was 0
  29.  
  30. a = 2 * rx ^ 2
  31. b = 2 * ry ^ 2
  32. x = rx
  33. xx = ry ^ 2 * (1 - 2 * rx)
  34. yy = rx ^ 2
  35. sx = b * rx
  36.  
  37. DO WHILE sx >= sy 'no = ? , nope that didn't help
  38.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  39.     IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  40.     y = y + 1
  41.     sy = sy + a
  42.     e = e + yy
  43.     yy = yy + a
  44.  
  45.     IF (2 * e + xx) > 0 THEN 'add = ? nope no fix
  46.         x = x - 1
  47.         sx = sx - b
  48.         e = e + xx
  49.         xx = xx + b
  50.     END IF
  51.  
  52. oldy = y ' Pete's fix
  53. x = 0
  54. y = ry
  55. xx = rx * ry
  56.  
  57. yy = rx ^ 2 * (1 - 2 * ry)
  58. e = 0
  59. sx = 0
  60. sy = a * ry
  61.  
  62.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  63.     LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  64.     DO
  65.         x = x + 1
  66.         sx = sx + b
  67.         e = e + xx
  68.         xx = xx + b
  69.     LOOP UNTIL (2 * e + yy) > 0 'add = ? nope no fix
  70.     y = y - 1
  71.     sy = sy - a
  72.     e = e + yy
  73.     yy = yy + a
  74. LOOP UNTIL y < oldy ' Pete's fix applied here.
  75.  
  76.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 10, 2019, 06:18:28 pm
R + R is faster than 2 * R
R * R is faster than R ^ 2

Certain operations have more overhead than others.  If you’re going to optimize for speed, choose the operator with the fastest performance.  ;)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 06:25:40 pm
That's what I wanted to know.

So, my fix applied with the fastest math method according to Steve would be...

Code: QB64: [Select]
  1. _TITLE "Ellipsefill from Steve"
  2. SCREEN _NEWIMAGE(1000, 700, 32)
  3. _SCREENMOVE 180, 20
  4. 'B+ 2019-02-10 resave this code to
  5. 'just test this code for proper filling without overlap, timed tests are else where
  6.  
  7. FOR i = 1 TO 400 'draw ellipse at various heights
  8.     CLS
  9.     PRINT "b Radius"; i; " Press any to get to 400, <backspace> to go back one, <esc> for next test."
  10.     EllipseFill 500, 350, 400, i, _RGBA(255, 255, 255, 40)
  11.     k$ = ""
  12.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  13.     IF k$ = CHR$(8) THEN i = i - 2
  14.     IF k$ = CHR$(27) THEN EXIT FOR
  15.  
  16. WHILE _KEYDOWN(32) = 0 'check all sorts random stuff
  17.     EllipseFill RND * 1000, RND * 700, RND * 100, RND * 100, _RGBA32(255 * RND, 255 * RND, 255 * RND, 100 * RND)
  18.     _LIMIT 1
  19.  
  20. ' with Steve's EllipseFill, who needs CircleFill? fix for 0 radii 2019-02-05
  21. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  22. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  23. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  24.  
  25. DIM sx AS LONG, sy AS LONG
  26.  
  27. IF rx = 0 OR ry = 0 THEN EXIT SUB 'nothing to draw, B+ added this to avoid errors when b was 0
  28.  
  29. a = 2 * rx * rx
  30. b = 2 * ry * ry
  31. x = rx
  32. xx = ry * ry * (1 - rx - rx)
  33. yy = rx * rx
  34. sx = b * rx
  35.  
  36. DO WHILE sx >= sy
  37.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  38.     IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  39.     y = y + 1
  40.     sy = sy + a
  41.     e = e + yy
  42.     yy = yy + a
  43.  
  44.     IF (e + e + xx) > 0 THEN
  45.         x = x - 1
  46.         sx = sx - b
  47.         e = e + xx
  48.         xx = xx + b
  49.     END IF
  50. oldy = y ' Pete's fix. Get the last fill position.
  51. x = 0
  52. y = ry
  53. xx = rx * ry
  54.  
  55. yy = rx * rx * (1 - ry - ry)
  56. e = 0
  57. sx = 0
  58. sy = a * ry
  59.  
  60.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  61.     LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  62.     DO
  63.         x = x + 1
  64.         sx = sx + b
  65.         e = e + xx
  66.         xx = xx + b
  67.     LOOP UNTIL (e + e + yy) > 0
  68.     y = y - 1
  69.     sy = sy - a
  70.     e = e + yy
  71.     yy = yy + a
  72. LOOP UNTIL y < oldy ' Pete's fix applied here.
  73.  
  74.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 06:34:06 pm
That's what I wanted to know.

So, my fix applied with the fastest math method according to Steve would be...

Code: QB64: [Select]
  1. _TITLE "Ellipsefill from Steve"
  2. SCREEN _NEWIMAGE(1000, 700, 32)
  3. _SCREENMOVE 180, 20
  4. 'B+ 2019-02-10 resave this code to
  5. 'just test this code for proper filling without overlap, timed tests are else where
  6.  
  7. FOR i = 1 TO 400 'draw ellipse at various heights
  8.     CLS
  9.     PRINT "b Radius"; i; " Press any to get to 400, <backspace> to go back one, <esc> for next test."
  10.     EllipseFill 500, 350, 400, i, _RGBA(255, 255, 255, 40)
  11.     k$ = ""
  12.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  13.     IF k$ = CHR$(8) THEN i = i - 2
  14.     IF k$ = CHR$(27) THEN EXIT FOR
  15.  
  16. WHILE _KEYDOWN(32) = 0 'check all sorts random stuff
  17.     EllipseFill RND * 1000, RND * 700, RND * 100, RND * 100, _RGBA32(255 * RND, 255 * RND, 255 * RND, 100 * RND)
  18.     _LIMIT 1
  19.  
  20. ' with Steve's EllipseFill, who needs CircleFill? fix for 0 radii 2019-02-05
  21. ' Is this fast enough for general circle fill (June 2018):  https://www.qb64.org/forum/index.php?topic=298.msg1942#msg1942
  22. '  EllipseFill SMcNeill (Nov 3, 2018) https://www.qb64.org/forum/index.php?topic=755.msg6506#msg6506
  23. SUB EllipseFill (cx AS INTEGER, cy AS INTEGER, rx AS INTEGER, ry AS INTEGER, c AS _UNSIGNED LONG)
  24.  
  25. DIM sx AS LONG, sy AS LONG
  26.  
  27. IF rx = 0 OR ry = 0 THEN EXIT SUB 'nothing to draw, B+ added this to avoid errors when b was 0
  28.  
  29. a = 2 * rx * rx
  30. b = 2 * ry * ry
  31. x = rx
  32. xx = ry * ry * (1 - rx - rx)
  33. yy = rx * rx
  34. sx = b * rx
  35.  
  36. DO WHILE sx >= sy
  37.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  38.     IF y <> 0 THEN LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  39.     y = y + 1
  40.     sy = sy + a
  41.     e = e + yy
  42.     yy = yy + a
  43.  
  44.     IF (e + e + xx) > 0 THEN
  45.         x = x - 1
  46.         sx = sx - b
  47.         e = e + xx
  48.         xx = xx + b
  49.     END IF
  50. oldy = y ' Pete's fix. Get the last fill position.
  51. x = 0
  52. y = ry
  53. xx = rx * ry
  54.  
  55. yy = rx * rx * (1 - ry - ry)
  56. e = 0
  57. sx = 0
  58. sy = a * ry
  59.  
  60.     LINE (cx - x, cy - y)-(cx + x, cy - y), c, BF
  61.     LINE (cx - x, cy + y)-(cx + x, cy + y), c, BF
  62.     DO
  63.         x = x + 1
  64.         sx = sx + b
  65.         e = e + xx
  66.         xx = xx + b
  67.     LOOP UNTIL (e + e + yy) > 0
  68.     y = y - 1
  69.     sy = sy - a
  70.     e = e + yy
  71.     yy = yy + a
  72. LOOP UNTIL y < oldy ' Pete's fix applied here.
  73.  
  74.  

And that is what I had in my timed tests and that is why I said Pete made no math changes.

we could change:
    a = 2 * rx * rx
    b = 2 * ry * ry

to a = rx*rx + rx*rx
    b = ry*ry + ry * ry
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 10, 2019, 06:43:47 pm
Quote
    a = 2 * rx * rx

to a = rx*rx + rx*rx

You’ll just be slower....

You’re going from 2 multiplication operations to 2 multiplication operations AND an addition operation.

Maybe:  a1 = rx * rx: a = a1 + a1  (If lookup times are faster)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 06:48:18 pm
Yep! Confirmed I changed it back.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 06:55:35 pm
So what Steve is saying is that...

R + R is faster than 2 * R
R * R is faster than R ^ 2

so for example in the original code...

xx = ry * ry * (1 - rx - rx) ' Original code

is faster than changing it to...

xx = ry * ry * (1 - 2 * rx)

I see you just changed it back to the original code, which should match the last one I posted, where I changed it back as well. So we should now have the fastest way to move through the equations, plus my fix the periodic fill problem. All good to go?

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 10, 2019, 07:37:19 pm
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.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 07:46:51 pm
And I just save hundreds by switching my car insurance to GEICO.

So 64-bit has too much memory allocated for more digits than needed, maybe, or just a fluke?

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 10, 2019, 07:55:05 pm
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.

And have fun playing with some of the math optimization flags.  They can drastically change your test times.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 10, 2019, 11:10:43 pm
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?

Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 10, 2019, 11:21:53 pm
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?

Afraid not.  I found it in an old QB45 program that was on an old drive of mine from ages ago.  I have no idea where the heck I originally acquired/derived it, and I didn’t take any notes as I tweaked it to remove duplicate lines in the past. (And it seems I still missed a few, but I think Pete’s fix corrects those.)

I’ll see if I can pull the original back up later (I have to reinstall the old 40GB drive and an IDE card/cable to use it), and see if the “boob effect” is there from the original, or introduced via alterations.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 10, 2019, 11:35:52 pm
I noticed we had an ellipse with tits, too... with some sizes... but seriously guys, you wanna change that??!

Pete :D
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 10, 2019, 11:47:31 pm
Although I'm from Massachusetts, I take a page out of the Texas playbook when it comes to certain anatomical preferences. I wish the tit effect would show up for BIG ellipses, not puny little pointy ones.

XD

I should modify my Tilted ellipse to include a Titted ellipse version as well...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 12:42:11 am
We can still make a fortune selling this to dress designers, who outfit super-models...  So, there's a bright side!

Pete :D
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 11, 2019, 01:06:58 am
Alright, so this function is optimized for clarity instead of speed, but has a lovely out-of-the-box feature of running about as fast as the one Steve brought in. Surely more speed can be injected into this thing, too.

Code: QB64: [Select]
  1. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  2.     DIM h2 AS LONG
  3.     DIM w2 AS LONG
  4.     DIM h2w2 AS LONG
  5.     DIM xi AS INTEGER
  6.     DIM dx AS INTEGER
  7.     DIM x AS INTEGER
  8.     DIM y AS INTEGER
  9.     w2 = a * a
  10.     h2 = b * b
  11.     h2w2 = h2 * w2
  12.     xi = a
  13.     dx = 0
  14.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  15.     FOR y = 1 TO b
  16.         FOR x = xi - dx + 1 TO 0 STEP -1
  17.             IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT FOR
  18.         NEXT
  19.         dx = xi - x
  20.         xi = x
  21.         LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  22.         LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  23.     NEXT

... just have to check it for bugs, boobs, or other artifacts.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 01:52:43 am
This one fails at various levels, too. Here is one, for example...

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2. _SCREENMOVE 180, 20
  3.  
  4. FlatEllipseFill 500, 350, 400, 200, _RGBA(255, 255, 255, 40)
  5.  
  6. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  7. DIM h2w2 AS LONG
  8. w2 = a * a
  9. h2 = b * b
  10. h2w2 = h2 * w2
  11. xi = a
  12. dx = 0
  13. LINE (ox - a, oy)-(ox + a, oy), col, BF
  14. FOR y = 1 TO b
  15.     FOR x = xi - dx + 1 TO 0 STEP -1
  16.         IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT FOR
  17.     NEXT
  18.     dx = xi - x
  19.     xi = x
  20.     LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  21.     LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  22.  

201 fails, too, but plug in 203 and it's fine.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Cobalt on February 11, 2019, 02:27:07 am
So what Steve is saying is that...
...
R * R is faster than R ^ 2
...
Pete

and _SHL\_SHR are even faster if dealing with powers of 2
so _SHL(R,1) should be faster than R^2 and R*R
only draw back is it has to be power of 2.

I like 2s, 2 eyes, 2 ears, 2 hands, 2 balls.., 2 teats.... life is full of 2s unless your a cow then its 4 teats(hey power of 2!) or pigs then its 8 teats (hey another power of 2!) not versed enough in animal biology does any animal have 16 teats?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 02:40:21 am
Siamese pigs.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 02:45:10 am
Bill, simple variable designation problem. LONG doesn't cut it, so....

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2. _SCREENMOVE 180, 20
  3.  
  4. FlatEllipseFill 500, 350, 400, 200, _RGBA(255, 255, 255, 40)
  5.  
  6. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  7. w2 = a * a
  8. h2 = b * b
  9. h2w2 = h2 * w2
  10. xi = a
  11. dx = 0
  12. LINE (ox - a, oy)-(ox + a, oy), col, BF
  13. FOR y = 1 TO b
  14.     FOR x = xi - dx + 1 TO 0 STEP -1
  15.         IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT FOR
  16.     NEXT
  17.     dx = xi - x
  18.     xi = x
  19.     LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  20.     LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  21.  

So I tested it with this, and no glitches. It will make a circle at 300 and then start on a vertical ellipse. It's also a fun effect if you omit the CLS and sleep. Stop it at 300 and you get a full moon effect.

Anyway, maybe something less than DOUBLE can be used but that for/next loop spits out some very large figures.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2. _SCREENMOVE 180, 20
  3.  
  4. FOR i = 1 TO 350
  5.     CLS
  6.     PRINT "300 x"; i
  7.     FlatEllipseFill 500, 350, 300, i, _RGBA(255, 255, 255, 40)
  8.     SLEEP
  9.  
  10. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  11. w2 = a * a
  12. h2 = b * b
  13. h2w2 = h2 * w2
  14. xi = a
  15. dx = 0
  16. LINE (ox - a, oy)-(ox + a, oy), col, BF
  17. FOR y = 1 TO b
  18.     FOR x = xi - dx + 1 TO 0 STEP -1
  19.         IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT FOR
  20.     NEXT
  21.     dx = xi - x
  22.     xi = x
  23.     LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  24.     LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  25.  

I was about half way through making one like this, after getting the formulas together to calculate the parts of an ellipse. Oh well, spoiler. Nice find, Bill...

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 11, 2019, 06:48:30 am
Ah, there are the finishing touches. I figured I was being lazy with respect to variable types but it was also pretty late. I blame Loki. So now I suppose we just wait for bplus to get hold of this...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 11, 2019, 10:19:36 am
Current fill routine for reference.
Code: QB64: [Select]
  1. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  2. w2 = a * a
  3. h2 = b * b
  4. h2w2 = h2 * w2
  5. xi = a
  6. dx = 0
  7. LINE (ox - a, oy)-(ox + a, oy), col, BF
  8. FOR y = 1 TO b
  9.     FOR x = xi - dx + 1 TO 0 STEP -1
  10.         IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT FOR
  11.     NEXT
  12.     dx = xi - x
  13.     xi = x
  14.     LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  15.     LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF


IMO this is optimized for clarity:
Code: QB64: [Select]
  1. SUB fEllipse (CX AS LONG, CY AS LONG, xRadius AS LONG, yRadius AS LONG, c AS _UNSIGNED LONG)
  2.     DIM scale AS SINGLE, x AS LONG, y AS LONG
  3.     IF xRadius = 0 OR yRadius = 0 THEN EXIT SUB  '<<<<<<<<<<<<< really do need to skip out with 0
  4.     scale = yRadius / xRadius
  5.     LINE (CX, CY - yRadius)-(CX, CY + yRadius), c, BF
  6.     FOR x = 1 TO xRadius
  7.         y = scale * SQR(xRadius * xRadius - x * x)
  8.         LINE (CX + x, CY - y)-(CX + x, CY + y), c, BF
  9.         LINE (CX - x, CY - y)-(CX - x, CY + y), c, BF
  10.     NEXT

STxAxTIC begins to obscure but optimize for speed by going around using the sq root function with this substitution for SQR, reworking this line:
Code: QB64: [Select]
  1. y = scale * SQR(xRadius * xRadius - x * x)
  2.  
to this: (except he reworks for x not y)
Code: QB64: [Select]
  1.    
  2.     FOR x = xi - dx + 1 TO 0 STEP -1
  3.         IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT FOR
  4.     NEXT
  5.     dx = xi - x
  6.     xi = x
  7.  
Sorry, this would be clearer if I stuck to same variable names and now I see he is changing X's not Y's when drawing 2 lines.
All that to avoid using SQR, wow! That actually clears up that part of Steve's version for me, thanks.

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.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 10:57:38 am
Other C programmershave posted this avoid using SQR method online so there is probably some reason for it. My question would be since this project is based on time.... What limits performance the most; using SQR or going from LONG to DOUBLE variables?  In other words, would SQR with LONG be faster or slower than avoiding SQR and using LONG?

Now the one Steve dug up is interesting in that it draws the ellipse in two stages. The only way that could possibly be faster is if part of an ellipse (certain axis) can use fewer calculations; so you use a quicker formula to draw that part and finish it off with the more complex computations in the other part. The problem with that method, as posted, is the boob effect, as Bill puts it. That's some yet unidentified math problem, but seriously, unless that two stage method is faster by design, it should be pitched, rather than corrected, in favor of a single drawing algorithm.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 11, 2019, 11:19:08 am
bplus:
Quote
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.

I was expecting FlatEllipseFill to run twice as long as CircleFill. Wrong! It is already running neck and neck with the proven CircleFill Routine!!!


I added the exit sub if either radius = 0 and I changed all the variables to LONG and I substituted the For loop with a While loop:
I am getting very nearly the same times, sometimes CircleFill faster, sometimes FlatEllipseFill:
Code: QB64: [Select]
  1. _TITLE "STATIC Ellipse Fill versus Steve Circle Fill"
  2. DEFINT A-Z
  3. SCREEN _NEWIMAGE(1220, 680, 32)
  4. _SCREENMOVE 100, 20
  5.  
  6. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  7. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  8. INPUT "EllipseFill (fel) overlap test, press enter to continue "; wate$
  9. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  10. start## = TIMER
  11. FOR i = 1 TO 10000
  12.     FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 100)
  13. EllipseTime## = TIMER - start##
  14. _PRINTSTRING (800, 615), "Time for 10000 EllipseFills:" + STR$(EllipseTime##)
  15.  
  16.  
  17. ' ==================================================== compare to the old gold standard
  18.  
  19. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  20. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  21. LOCATE 1, 1: INPUT "CircleFill overlap test, press enter to continue "; wate$
  22. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  23.  
  24. start## = TIMER
  25. FOR i = 1 TO 10000
  26.     CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 100)
  27. OldCircleTime## = TIMER - start##
  28. _PRINTSTRING (200, 615), "Time for 10000 Circle Fills:" + STR$(OldCircleTime##)
  29.  
  30. 'old circle fill
  31. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  32.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  33.     DIM X AS INTEGER, Y AS INTEGER
  34.  
  35.     Radius = ABS(R)
  36.     RadiusError = -Radius
  37.     X = Radius
  38.     Y = 0
  39.  
  40.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  41.  
  42.     ' Draw the middle span here so we don't draw it twice in the main loop,
  43.     ' which would be a problem with blending turned on.
  44.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  45.  
  46.     WHILE X > Y
  47.         RadiusError = RadiusError + Y * 2 + 1
  48.         IF RadiusError >= 0 THEN
  49.             IF X <> Y + 1 THEN
  50.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  51.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  52.             END IF
  53.             X = X - 1
  54.             RadiusError = RadiusError - X * 2
  55.         END IF
  56.         Y = Y + 1
  57.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  58.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  59.     WEND
  60.  
  61.  
  62. SUB FlatEllipseFill (ox AS LONG, oy AS LONG, a AS LONG, b AS LONG, col AS _UNSIGNED LONG)
  63.     DIM h2 AS LONG
  64.     DIM w2 AS LONG
  65.     DIM h2w2 AS LONG
  66.     DIM xi AS LONG
  67.     DIM dx AS LONG
  68.     DIM x AS LONG
  69.     DIM y AS LONG
  70.     IF a = 0 OR b = 0 THEN EXIT SUB ' B+ added this
  71.     w2 = a * a
  72.     h2 = b * b
  73.     h2w2 = h2 * w2
  74.     xi = a
  75.     dx = 0
  76.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  77.     y = 0 ' B+ added this to eliminate FOR loop
  78.     WHILE y < b 'b+ no FOR loop
  79.         y = y + 1
  80.         FOR x = xi - dx + 1 TO 0 STEP -1
  81.             IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT FOR
  82.         NEXT
  83.         dx = xi - x
  84.         xi = x
  85.         LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  86.         LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  87.     WEND
  88.  
  89.  

So even CircleFill can be pitched as FlatEllipseFill could serve as both a Circle Fill and a Flat Ellipse Fill (as I was going to do with Steve's EllipseFill before the nipple problem was discovered).

Oh dang it, another For loop yet to go!
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 11:44:44 am
We already went over variable types that won't work. Just try this...

FlatEllipseFill 915, 305, 400, 200, _RGBA32(0, 100, 0, 40)

That's not an ellipse with variable types using LONG, 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. I know Bill used LONG and INTEGER, which is too limited a type for this... but I just threw in DOUBLE everywhere, which is overkill. I decided to work on some of the numbers and post back...

Pete



Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 11, 2019, 12:04:40 pm
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

Sorry, missed that. It's probably the H2W2 number, squaring a square, say a = 400 b = 200 a^2 *b^2 = 6.4 x 10^9
but you say 202 works???
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 12:08:56 pm
I just edited the post, because it was confusing.

I tried some work with the numbers and this seems to be working out so far...

DIM h2 AS DOUBLE
DIM w2 AS DOUBLE
DIM h2w2 AS DOUBLE
DIM xi AS INTEGER
DIM dx AS INTEGER
DIM x AS INTEGER
DIM y AS INTEGER

I don't need to use a variety of variable types in my work, so feel free to tear into this as needed. I may look into it a _bit more, too.

So far, so good. Running several simulations and it looks to be behaving. Apparently, only the right side of that equation needs to have DOUBLE as the variable type.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 11, 2019, 12:56:12 pm
From experimenting with following, I think you have to type them all to cover the max value w2h2 can take:
Code: QB64: [Select]
  1. _TITLE "long type test"
  2. DIM test AS LONG, big AS _INTEGER64
  3. test = 100 'test olny made it to 215 ^ 4 !!!
  4. big = test * test * test * test
  5. WHILE big > 0 AND test < 1500
  6.     test = test + 1
  7.     big = test * test * test * test
  8. PRINT test, big, (test - 1) ^ 4
  9.  
  10.  
switch test from LONG type to _INTEGER64
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 11, 2019, 01:17:45 pm
As Pete warned this code did pick up errors at certain a, b with everything LONG, but runs fine with everything at _INTEGER64:
Code: QB64: [Select]
  1. _TITLE "Flat Ellipse Fill (dimensions) test" 'edit: fix title
  2.  
  3. SCREEN _NEWIMAGE(1000, 700, 32)
  4. _SCREENMOVE 180, 20
  5. 'B+ 2019-02-10 resave this code to
  6. 'just test this code for proper filling without overlap, timed tests are else where
  7.  
  8. FOR i = 0 TO 350 'draw ellipse at various heights
  9.  
  10.     CLS
  11.     PRINT "b Radius"; i; "   press any to get to 400, <backspace> to go back one, <esc> for next test."
  12.  
  13.     FlatEllipseFill 500, 350, 400, i, _RGBA(255, 255, 255, 40)
  14.     'k$ = ""
  15.     'WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  16.     'IF k$ = CHR$(8) THEN i = i - 2
  17.     'IF k$ = CHR$(27) THEN EXIT FOR
  18.     _DISPLAY
  19.     _LIMIT 5
  20.  
  21. FOR i = 0 TO 350 'draw ellipse at various heights
  22.  
  23.     CLS
  24.     PRINT "b Radius"; i; "   press any to get to 400, <backspace> to go back one, <esc> for next test."
  25.  
  26.     FlatEllipseFill 500, 350, i, 345, _RGBA(255, 255, 255, 40)
  27.     'k$ = ""
  28.     'WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  29.     'IF k$ = CHR$(8) THEN i = i - 2
  30.     'IF k$ = CHR$(27) THEN EXIT FOR
  31.     _DISPLAY
  32.     _LIMIT 5
  33.  
  34.  
  35. WHILE _KEYDOWN(32) = 0 'check all sorts random stuff
  36.     FlatEllipseFill RND * 1000, RND * 700, RND * 100, RND * 100, _RGBA32(255 * RND, 255 * RND, 255 * RND, 100 * RND)
  37.     _DISPLAY
  38.     _LIMIT 1
  39.  
  40.  
  41. SUB FlatEllipseFill (ox AS _INTEGER64, oy AS _INTEGER64, a AS _INTEGER64, b AS _INTEGER64, col AS _UNSIGNED LONG)
  42.     DIM h2 AS _INTEGER64
  43.     DIM w2 AS _INTEGER64
  44.     DIM h2w2 AS _INTEGER64
  45.     DIM xi AS _INTEGER64
  46.     DIM dx AS _INTEGER64
  47.     DIM x AS _INTEGER64
  48.     DIM y AS _INTEGER64
  49.     IF a = 0 OR b = 0 THEN EXIT SUB ' B+ added this
  50.     w2 = a * a
  51.     h2 = b * b
  52.     h2w2 = h2 * w2
  53.     xi = a
  54.     dx = 0
  55.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  56.     y = 0 ' B+ added this to eliminate FOR loop
  57.     WHILE y < b 'b+ no FOR loop
  58.         y = y + 1
  59.         x = xi - dx + 2
  60.         WHILE x >= 1
  61.             x = x - 1
  62.             IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT WHILE
  63.         WEND
  64.         dx = xi - x
  65.         xi = x
  66.         LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  67.         LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  68.     WEND
  69.  
  70.  

I confess a certain a bias to keeping everything out of float types.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 11, 2019, 01:24:15 pm
Flat Ellipse Fill with all variables at _INTEGER64 is still running neck and neck with Circle Fill, sometimes one or the other has the better time but Circle Fill has the lowest time that I've seen over many tests.

Code: QB64: [Select]
  1. _TITLE "STATIC Ellipse Fill versus Steve Circle Fill"
  2. DEFINT A-Z
  3. SCREEN _NEWIMAGE(1220, 680, 32)
  4. _SCREENMOVE 100, 20
  5.  
  6. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  7. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  8. INPUT "Flat EllipseFill overlap test, press enter to continue "; wate$
  9. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  10. start## = TIMER
  11. FOR i = 1 TO 10000
  12.     FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 100)
  13. EllipseTime## = TIMER - start##
  14. _PRINTSTRING (800, 615), "Time for 10000 Flat Ellipse Fills:" + STR$(EllipseTime##)
  15.  
  16.  
  17. ' ==================================================== compare to the old gold standard
  18.  
  19. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  20. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  21. LOCATE 1, 1: INPUT "CircleFill overlap test, press enter to continue "; wate$
  22. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  23.  
  24. start## = TIMER
  25. FOR i = 1 TO 10000
  26.     CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 100)
  27. OldCircleTime## = TIMER - start##
  28. _PRINTSTRING (200, 615), "Time for 10000 Circle Fills:" + STR$(OldCircleTime##)
  29.  
  30. 'old circle fill
  31. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  32.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  33.     DIM X AS INTEGER, Y AS INTEGER
  34.  
  35.     Radius = ABS(R)
  36.     RadiusError = -Radius
  37.     X = Radius
  38.     Y = 0
  39.  
  40.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  41.  
  42.     ' Draw the middle span here so we don't draw it twice in the main loop,
  43.     ' which would be a problem with blending turned on.
  44.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  45.  
  46.     WHILE X > Y
  47.         RadiusError = RadiusError + Y * 2 + 1
  48.         IF RadiusError >= 0 THEN
  49.             IF X <> Y + 1 THEN
  50.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  51.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  52.             END IF
  53.             X = X - 1
  54.             RadiusError = RadiusError - X * 2
  55.         END IF
  56.         Y = Y + 1
  57.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  58.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  59.     WEND
  60.  
  61.  
  62. SUB FlatEllipseFill (ox AS _INTEGER64, oy AS _INTEGER64, a AS _INTEGER64, b AS _INTEGER64, col AS _UNSIGNED LONG)
  63.     DIM h2 AS _INTEGER64
  64.     DIM w2 AS _INTEGER64
  65.     DIM h2w2 AS _INTEGER64
  66.     DIM xi AS _INTEGER64
  67.     DIM dx AS _INTEGER64
  68.     DIM x AS _INTEGER64
  69.     DIM y AS _INTEGER64
  70.     IF a = 0 OR b = 0 THEN EXIT SUB ' B+ added this
  71.     w2 = a * a
  72.     h2 = b * b
  73.     h2w2 = h2 * w2
  74.     xi = a
  75.     dx = 0
  76.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  77.     y = 0 ' B+ added this to eliminate FOR loop
  78.     WHILE y < b 'b+ no FOR loop
  79.         y = y + 1
  80.         x = xi - dx + 2
  81.         WHILE x >= 1
  82.             x = x - 1
  83.             IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT WHILE
  84.         WEND
  85.         dx = xi - x
  86.         xi = x
  87.         LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  88.         LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  89.     WEND
  90.  
  91.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 11, 2019, 01:47:32 pm
Would using INTEGERS run any faster? My tests I've been running showed me that what I posted previously is true, that only the right side of that equation needed more range, so...

DIM xi AS _INTEGER64
DIM dx AS _INTEGER64
DIM x AS _INTEGER64
DIM y AS _INTEGER64

Could be changed to...

DIM xi AS INTEGER
DIM dx AS INTEGER
DIM x AS INTEGER
DIM y AS INTEGER

Yep, just tested some runs. So you could use...

DIM h2 AS _INTEGER64
DIM w2 AS _INTEGER64
DIM h2w2 AS _INTEGER64
DIM xi AS INTEGER
DIM dx AS INTEGER
DIM x AS INTEGER
DIM y AS INTEGER

In any event, it looks like we have something coming along that meets the requirements nicely. By we, I mean you guys. Sorry I can't be a bigger contributor here. This just isn't my area, but it's fun, and I managed to conjure up a couple of bug fixes.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 11, 2019, 06:22:51 pm
Concerning optimizing Type Declarations, I think (or intuit) choosing the largest type needed to do and contain all calculations for all the variables involved and to specially avoid mixing float types with integer types.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 11, 2019, 10:22:27 pm
Ooookay where were we? First thought: a speed comparison between a raw circle fill versus an ellipse fill is somewhat of a foregone conclusion. Circles are the simplest shape in the universe, so they had better fill in quickly. Is there room for both functions in the new up-and-coming Toolbox? Hell yes, for two reasons: (i) the forum is empty right now and real estate over there is cheap, and (ii) people who still call them "ovals" probably never heard of ellipses, so those folks may be left wondering how to fill in their circles despite having glazed over a solution.

As an aside, it's lovely that the ellipse and circle-filling functions run at comparable speeds, so minimalists can just download an ellipse-filling routine and be done with the question.

After 5 forum pages I think we may have a few products. You guys are incredibly resilient for sticking to this.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 04:29:44 am
So here's what we have so far with two things I added/changed...

1) Added new variable to reduce equation steps: yyw2 = y * y * w2
2) Substituted DO/LOOP in place of FOR/LOOP for speed considerations.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2.  
  3. FlatEllipseFill 500, 350, 350, 200, _RGBA(255, 255, 255, 40)
  4.  
  5. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  6. IF a = 0 OR b = 0 THEN EXIT SUB
  7. w2 = a * a
  8. h2 = b * b
  9. h2w2 = h2 * w2
  10. xi = a
  11. dx = 0
  12. y = 0
  13. LINE (ox - a, oy)-(ox + a, oy), col, BF
  14.     y = y + 1
  15.     yyw2 = y * y * w2
  16.     x = xi - dx + 1
  17.     DO
  18.         IF x * x * h2 + yyw2 <= h2w2 THEN EXIT DO
  19.         x = x - 1
  20.     LOOP
  21.     dx = xi - x
  22.     xi = x
  23.     LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  24.     LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  25. LOOP UNTIL y = b
  26.  

I don't think it is as elegant with these changes, but since speed is the goal, so be it.

A DO/LOOP actually requires one additional statement than a FOR/NEXT, but if you guys are sure it's still faster, it's all good this way. 

There might be some more optimization possible in these equations and this geometric progression looping approach. Maybe Steve could use his index approach to cut down the number of loops needed, but my guess would be the added conditional statements might add too much time and make it a push at best.

I posted a quick demo using this method at: https://www.tapatalk.com/groups/qbasic/viewtopic.php?f=648955&t=39432

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 12, 2019, 07:00:25 am
DO...LOOP is faster than FOR...NEXT just from the way they’re translated into C.  I’ll post a few simple examples in a different topic later, so as to not clutter up this one, but DO will always outperform FOR, from my experience.  (Only by a little, but when speed is the goal, each microsecond adds up.)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 10:12:35 am
The thing Fell likes best about this thread is the KTMB Principle. (Keep the monkeys busy!)

Well, in terms of speed, should we be careful what we wish for, because if DO/LOOP is faster than FOR/NEXT, that's isn't so bad, but do you think GOTO could be faster, still?

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2.  
  3. FlatEllipseFill 500, 350, 350, 200, _RGBA(255, 255, 255, 40)
  4.  
  5. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  6. IF a = 0 OR b = 0 THEN EXIT SUB
  7. w2 = a * a
  8. h2 = b * b
  9. h2w2 = h2 * w2
  10. xi = a
  11. dx = 0
  12. y = 0
  13. LINE (ox - a, oy)-(ox + a, oy), col, BF
  14. 100
  15. y = y + 1
  16. yyw2 = y * y * w2
  17. x = xi - dx + 1
  18. 101
  19. IF x * x * h2 + yyw2 <= h2w2 THEN 102
  20. x = x - 1
  21. GOTO 101
  22. 102
  23. dx = xi - x
  24. xi = x
  25. LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  26. LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  27. IF y < b THEN 100
  28.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: _vince on February 12, 2019, 10:40:15 am
further optimized version of steve's amazing algorithm ;-)
comment out the last line in the sub ;-)

Code: QB64: [Select]
  1. sub ellipsef(x0, y0, rx, ry, c)
  2.     a = 2*rx*rx
  3.     b = 2*ry*ry
  4.    
  5.    
  6.     x = 0
  7.     y = ry
  8.     dx = ry*ry
  9.     dy = rx*rx*(1 - 2*ry)
  10.     e = 0
  11.     sx = 0
  12.     sy = a*ry
  13.    
  14.     do while sx <= sy
  15.         line (x0 - x, y0 + y)-step(2*x, 0),c,bf
  16.         line (x0 - x, y0 - y)-step(2*x, 0),c,bf
  17.        
  18.         x = x + 1
  19.         sx = sx + b
  20.         e = e + dx
  21.         dx = dx + b
  22.        
  23.         if 2*e + dy > 0 then
  24.             y = y - 1
  25.             sy = sy - a
  26.             e = e + dy
  27.             dy = dy + a
  28.         end if
  29.     loop
  30.    
  31.     x1 = x0 - x
  32.     x2 = x0 + x
  33.     y1 = y0 - y
  34.    
  35.     x = rx
  36.     y = 0
  37.     dx = ry*ry*(1 - 2*rx)
  38.     dy = rx*rx
  39.     e = 0
  40.     sx = b*rx
  41.     sy = 0
  42.    
  43.     x3 = x0 - x
  44.    
  45.     do while sx >= sy
  46.         line (x0 - x, y0 + y)-(x1, y0 + y),c,bf
  47.         line (x0 - x, y0 - y)-(x1, y0 - y),c,bf
  48.         line (x0 + x, y0 + y)-(x2, y0 + y),c,bf
  49.         line (x0 + x, y0 - y)-(x2, y0 - y),c,bf
  50.        
  51.         y = y + 1
  52.         sy = sy + a
  53.         e = e + dy
  54.         dy = dy + a
  55.        
  56.         if 2*e + dx > 0 then
  57.             x = x - 1    
  58.             sx = sx - b
  59.             e = e + dx
  60.             dx = dx + b
  61.         end if
  62.     loop
  63.    
  64.     line (x1, y1)-(x2,y0 + y),c,bf  
  65.    
  66.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 10:50:28 am
Pete, you want to draw something even if a or b is 0?

Vince, does your version take care of the nipple problem?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 10:57:01 am
I'll have to see what Vince posted in a minute, but right now this new one we are working on had me wondering why we need that inner loop at all. I mean why not just solve for x algebraically?

x = INT(SQR((h2w2 - yyw2) / h2))

I'll post back with an example, soon...

Pete

Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 11:02:43 am
Well, it worked for one run. Now I have to test it with multiple sizes...

MODIFIED SINGLE LOOP ELLIPSE FILL SUB ROUTINE. (Solved algebraically.)

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2.  
  3. FlatEllipseFill 500, 350, 350, 200, _RGBA(255, 255, 255, 40)
  4.  
  5. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  6. IF a = 0 OR b = 0 THEN EXIT SUB
  7. w2 = a * a
  8. h2 = b * b
  9. h2w2 = h2 * w2
  10. x = a
  11. y = 0
  12. LINE (ox - a, oy)-(ox + a, oy), col, BF
  13. 100
  14. y = y + 1
  15. yyw2 = y * y * w2
  16. x = INT(SQR((h2w2 - yyw2) / h2))
  17. LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  18. LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  19. IF y < b THEN 100
  20.  

So we also got rid of some lines by removing unnecessary loop variables. I just left the GOTO part in this one. It can easily be swapped out for DO/LOOP if GOTO isn't faster.

Pete

Edit: Yea! It works!
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 11:08:00 am
further optimized version of steve's amazing algorithm ;-)
comment out the last line in the sub ;-)

Code: QB64: [Select]
  1. sub ellipsef(x0, y0, rx, ry, c)
  2.     a = 2*rx*rx
  3.     b = 2*ry*ry
  4.    
  5.    
  6.     x = 0
  7.     y = ry
  8.     dx = ry*ry
  9.     dy = rx*rx*(1 - 2*ry)
  10.     e = 0
  11.     sx = 0
  12.     sy = a*ry
  13.    
  14.     do while sx <= sy
  15.         line (x0 - x, y0 + y)-step(2*x, 0),c,bf
  16.         line (x0 - x, y0 - y)-step(2*x, 0),c,bf
  17.        
  18.         x = x + 1
  19.         sx = sx + b
  20.         e = e + dx
  21.         dx = dx + b
  22.        
  23.         if 2*e + dy > 0 then
  24.             y = y - 1
  25.             sy = sy - a
  26.             e = e + dy
  27.             dy = dy + a
  28.         end if
  29.     loop
  30.    
  31.     x1 = x0 - x
  32.     x2 = x0 + x
  33.     y1 = y0 - y
  34.    
  35.     x = rx
  36.     y = 0
  37.     dx = ry*ry*(1 - 2*rx)
  38.     dy = rx*rx
  39.     e = 0
  40.     sx = b*rx
  41.     sy = 0
  42.    
  43.     x3 = x0 - x
  44.    
  45.     do while sx >= sy
  46.         line (x0 - x, y0 + y)-(x1, y0 + y),c,bf
  47.         line (x0 - x, y0 - y)-(x1, y0 - y),c,bf
  48.         line (x0 + x, y0 + y)-(x2, y0 + y),c,bf
  49.         line (x0 + x, y0 - y)-(x2, y0 - y),c,bf
  50.        
  51.         y = y + 1
  52.         sy = sy + a
  53.         e = e + dy
  54.         dy = dy + a
  55.        
  56.         if 2*e + dx > 0 then
  57.             x = x - 1    
  58.             sx = sx - b
  59.             e = e + dx
  60.             dx = dx + b
  61.         end if
  62.     loop
  63.    
  64.     line (x1, y1)-(x2,y0 + y),c,bf  
  65.    
  66.  

Yikes! Vince, here is my overlap test of your code (with last line in sub commented out)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: _vince on February 12, 2019, 11:14:29 am
The idea is there, a single LINE BF is going to be much faster than manually filling all of that in.  I'd need to review Steve's derivation notes to fix the overlap issue
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 11:15:21 am
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
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 11:28:38 am
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

Yes, I ran a timed test on it and was shocked! Even with BOTH the extra SQR AND INT functions it was comparable to the old Gold Standard Circle Fill. ;-)) Is the INT function needed?

Append:
Code: QB64: [Select]
  1. IF a = 0 OR b = 0 THEN EXIT SUB
Oh! I see it now, the first line, sorry, I was expecting it after DIM statements.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 11:34:20 am
I just edited (cleaned it up a bit) while you were posting. I'm still checking some things with the DIM statements to work around multiple calls. I'll post that version, soon.

This integral calculus stuff is fun. It takes me back to when I was a kid in school. Ah, to be 7 again! :D :D :D

Pete

OK, edited back to this thread to post the latest. A bit more cleaned up and it only goes through the DIM list once, so those statements won't be used again for multiple ellipse fills.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2.  
  3. FOR i = 1 TO 350
  4.     CLS
  5.     PRINT "Width = 350 Height ="; i; " Press a key to expand height..."
  6.     FlatEllipseFill 500, 350, 350, i, _RGBA(255, 255, 255, 40)
  7.     _DISPLAY
  8.     SLEEP
  9.  
  10. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  11. IF a = 0 OR b = 0 THEN EXIT SUB
  12. STATIC pete
  13. IF pete = 0 THEN
  14.     pete = -1
  15.     DIM h2 AS _INTEGER64
  16.     DIM w2 AS _INTEGER64
  17.     DIM h2w2 AS _INTEGER64
  18.     DIM yyw2 AS _INTEGER64
  19.     DIM x AS INTEGER
  20.     DIM y AS INTEGER
  21. w2 = a * a
  22. h2 = b * b
  23. h2w2 = h2 * w2
  24. x = a
  25. y = 0
  26. LINE (ox - a, oy)-(ox + a, oy), col, BF
  27. 100
  28. y = y + 1
  29. yyw2 = y * y * w2
  30. x = SQR((h2w2 - yyw2) / h2)
  31. LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  32. LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  33. IF y < b THEN 100
  34.  

I still think there might be some more equation optimization that could be achieved here, but maybe it is as cooked as it can get. Anyway, it is getting better!
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 11:59:49 am
Pete, at 1000 redraws of 300 radius circle the times are exactly the same but when I test 10000 then the CircleFilled routine consistently out paces the FlatEllipseFill routine. I did remove INT function and have yet to test overlap on all different sizes a, b.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 12:15:43 pm
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
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 12, 2019, 12:37:02 pm
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.  ;)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 12:53:33 pm
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.  ;)

Well that bypass routine can be removed then. Now unless there is a way of changing the SQR calculation, I think I'm at an end point on this one. OMG, wait a minute, if we don't need the DIM bypass, that means we have to pitch the variable "pete" which is used to bypass the DIM statements. You ***tard! :D

DIM Pete as _PISSED_OFFSET

Anyway guys, which do you think will win out in a speed test, GOTO or DO/LOOP? I hope they are the same or DO/LOOP wins. GOTO is just too ugly to put in a function.

Final thought. You know the y = 0 is not needed, but I've kept it there for something we need to discuss if this or any of these submissions becomes part of the tool box, we need to come up with variable names unique to the function. The ones we are playing around with here could easily intefer with other coders global variables.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 01:22:45 pm
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?

I did test that one time and GOTO had no advantage and might have been slower.
Code: QB64: [Select]
  1. DEFLNG A-Z
  2. PRINT "Running 2 timed tests please wait..."
  3.  
  4. n = 1000000000
  5.  
  6. t! = TIMER
  7. x = 0: i = 0
  8. doloop:
  9. i = i + 1
  10. x = x + i
  11. IF i < n THEN GOTO doloop
  12. t2! = TIMER
  13.  
  14. x = 0: i = 0
  15. WHILE i < n
  16.     i = i + 1
  17.     x = x + i
  18. t3! = TIMER
  19. PRINT n; " times adding in While... Wend time is "; t3! - t2!
  20. PRINT n; "     times adding in GOTO loop time is "; t2! - t!
  21.  
  22.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 12, 2019, 01:32:24 pm
Code: QB64: [Select]
  1. STATIC pete
  2. IF pete = 0 THEN
  3.     pete = -1
  4.     DIM h2 AS _INTEGER64
  5.     DIM w2 AS _INTEGER64
  6.     DIM h2w2 AS _INTEGER64
  7.     DIM yyw2 AS _INTEGER64
  8.     DIM x AS INTEGER
  9.     DIM y AS INTEGER

The above may not be useful, but the concept behind it holds promise...

Perhaps the following can make a speed difference:

STATIC h2 AS _INTEGER64
STATIC w2 AS _INTEGER64

And so on...

The idea is to not initialize/free temp variables, speeding the overall process up as much as possible.  Just be careful not to reuse values between SUB calls.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 01:50:51 pm
Steve, Yes, I thought of using STATIC that way, too, but no go, because all of those values are subject to change when a new different sized ellipse is made. I mean as a constant, sure w2 will always be a * a, but each time a new ellipse is made, with a new value for a, that equation has to be redone in the sub.

Mark, I'll get rid of the GOTO. Thanks for testing that.

This looks like my finished modifications. I also removed the y = 0 part, as I presume if this gets put into the tool box forum we will talk about renaming the variables to less commonly used names, names unique to the sub.

Code: QB64: [Select]
  1. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  2. IF a = 0 OR b = 0 THEN EXIT SUB
  3. w2 = a * a
  4. h2 = b * b
  5. h2w2 = h2 * w2
  6. x = a
  7. LINE (ox - a, oy)-(ox + a, oy), col, BF
  8.     y = y + 1
  9.     yyw2 = y * y * w2
  10.     x = SQR((h2w2 - yyw2) / h2)
  11.     LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  12.     LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  13. LOOP UNTIL y = b

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 12, 2019, 02:43:02 pm
I'm blown away that a version of the function that includes SQR is actually performing quickly!

A deep bow for having the balls to try that out again!

As for variable names - scope should save us. As part of good design, we should avoid globals (DIM SHAREDs) whenever possible, and there should be no collision whatsoever between simple variables like "y" causing interference. If it's *other* functions/subs/elements in someone's program that cause a problem with variable names, we shouldn't be obligated to hold their hand on this. Then again, qb64 functions have a bug (I refuse to call this a feature, it's a genuine "bad part") where functions can edit variables passed to them. Just terrible, and I always code to avoid being bitten by this. If we need to muck around with variable names to save people from being confused, then so be it I suppose.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 02:53:40 pm
Code: QB64: [Select]
  1. _TITLE "STATIC Ellipse Fill versus Steve Circle Fill"
  2. DEFINT A-Z
  3. SCREEN _NEWIMAGE(1220, 680, 32)
  4. _SCREENMOVE 100, 20
  5.  
  6. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  7. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  8. INPUT "Flat EllipseFill overlap test, press enter to continue "; wate$
  9. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  10. start## = TIMER
  11. FOR i = 1 TO 10000
  12.     FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 100)
  13. EllipseTime## = TIMER - start##
  14. _PRINTSTRING (800, 615), "Time for 10000 Flat Ellipse Fills:" + STR$(EllipseTime##)
  15.  
  16.  
  17. ' ==================================================== compare to the old gold standard
  18.  
  19. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  20. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  21. LOCATE 1, 1: INPUT "CircleFill overlap test, press enter to continue "; wate$
  22. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  23.  
  24. start## = TIMER
  25. FOR i = 1 TO 10000
  26.     CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 100)
  27. OldCircleTime## = TIMER - start##
  28. _PRINTSTRING (200, 615), "Time for 10000 Circle Fills:" + STR$(OldCircleTime##)
  29.  
  30. 'old circle fill
  31. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  32.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  33.     DIM X AS INTEGER, Y AS INTEGER
  34.  
  35.     Radius = ABS(R)
  36.     RadiusError = -Radius
  37.     X = Radius
  38.     Y = 0
  39.  
  40.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  41.  
  42.     ' Draw the middle span here so we don't draw it twice in the main loop,
  43.     ' which would be a problem with blending turned on.
  44.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  45.  
  46.     WHILE X > Y
  47.         RadiusError = RadiusError + Y * 2 + 1
  48.         IF RadiusError >= 0 THEN
  49.             IF X <> Y + 1 THEN
  50.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  51.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  52.             END IF
  53.             X = X - 1
  54.             RadiusError = RadiusError - X * 2
  55.         END IF
  56.         Y = Y + 1
  57.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  58.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  59.     WEND
  60.  
  61.  
  62. SUB FlatEllipseFill (ox AS _INTEGER64, oy AS _INTEGER64, a AS _INTEGER64, b AS _INTEGER64, col AS _UNSIGNED LONG)
  63.     DIM h2 AS _INTEGER64
  64.     DIM w2 AS _INTEGER64
  65.     DIM h2w2 AS _INTEGER64
  66.     DIM xi AS _INTEGER64
  67.     DIM dx AS _INTEGER64
  68.     DIM x AS _INTEGER64
  69.     DIM y AS _INTEGER64
  70.     IF a = 0 OR b = 0 THEN EXIT SUB ' B+ added this
  71.     w2 = a * a
  72.     h2 = b * b
  73.     h2w2 = h2 * w2
  74.     xi = a
  75.     dx = 0
  76.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  77.     ''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''''' y = 0 ' B+ added this to eliminate FOR loop
  78.     WHILE y < b 'b+ no FOR loop
  79.         y = y + 1
  80.         x = xi - dx + 2
  81.         WHILE x >= 1
  82.             x = x - 1
  83.             IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT WHILE
  84.         WEND
  85.         dx = xi - x
  86.         xi = x
  87.         LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  88.         LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  89.     WEND
  90.  
  91.  

I commented out one line in above code and now it is consistently matching or beating the Gold Standard Circle fill AND matching Circle fill's lowest time.

Here is the code for test I am using:
Code: QB64: [Select]
  1. _TITLE "STATIC Ellipse Fill versus Steve Circle Fill"
  2. '2019-02-12 add Pete's variation
  3.  
  4.  
  5. SCREEN _NEWIMAGE(1220, 680, 32)
  6. _SCREENMOVE 100, 20
  7.  
  8. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  9. FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 40)
  10. INPUT "Flat EllipseFill overlap test, press enter to continue "; wate$
  11. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  12. start## = TIMER
  13. FOR i = 1 TO 10000
  14.     FlatEllipseFill 915, 305, 300, 300, _RGBA32(0, 100, 0, 100)
  15. EllipseTime## = TIMER - start##
  16. _PRINTSTRING (800, 615), "Time for 10000 Flat Ellipse Fills:" + STR$(EllipseTime##)
  17.  
  18.  
  19. ' ==================================================== compare to the old gold standard
  20.  
  21. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  22. CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 40)
  23. LOCATE 1, 1: INPUT "CircleFill overlap test, press enter to continue "; wate$
  24. LINE (0, 0)-(600, 20), _RGB32(0, 0, 0), BF
  25.  
  26. start## = TIMER
  27. FOR i = 1 TO 10000
  28.     CircleFill 305, 305, 300, _RGBA32(0, 100, 0, 100)
  29. OldCircleTime## = TIMER - start##
  30. _PRINTSTRING (200, 615), "Time for 10000 Circle Fills:" + STR$(OldCircleTime##)
  31.  
  32. 'old circle fill
  33. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  34.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  35.     DIM X AS INTEGER, Y AS INTEGER
  36.  
  37.     Radius = ABS(R)
  38.     RadiusError = -Radius
  39.     X = Radius
  40.     Y = 0
  41.  
  42.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  43.  
  44.     ' Draw the middle span here so we don't draw it twice in the main loop,
  45.     ' which would be a problem with blending turned on.
  46.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  47.  
  48.     WHILE X > Y
  49.         RadiusError = RadiusError + Y * 2 + 1
  50.         IF RadiusError >= 0 THEN
  51.             IF X <> Y + 1 THEN
  52.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  53.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  54.             END IF
  55.             X = X - 1
  56.             RadiusError = RadiusError - X * 2
  57.         END IF
  58.         Y = Y + 1
  59.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  60.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  61.     WEND
  62.  
  63.  
  64. SUB FlatEllipseFill (ox AS _INTEGER64, oy AS _INTEGER64, a AS _INTEGER64, b AS _INTEGER64, col AS _UNSIGNED LONG)
  65.     DIM h2 AS _INTEGER64
  66.     DIM w2 AS _INTEGER64
  67.     DIM h2w2 AS _INTEGER64
  68.     DIM xi AS _INTEGER64
  69.     DIM dx AS _INTEGER64
  70.     DIM x AS _INTEGER64
  71.     DIM y AS _INTEGER64
  72.     IF a = 0 OR b = 0 THEN EXIT SUB ' B+ added this
  73.     w2 = a * a
  74.     h2 = b * b
  75.     h2w2 = h2 * w2
  76.     xi = a
  77.     dx = 0
  78.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  79.     'y = 0 ' B+ added this to eliminate FOR loop
  80.     WHILE y < b 'b+ no FOR loop
  81.         y = y + 1
  82.         x = xi - dx + 2
  83.         WHILE x >= 1
  84.             x = x - 1
  85.             IF x * x * h2 + y * y * w2 <= h2w2 THEN EXIT WHILE
  86.         WEND
  87.         dx = xi - x
  88.         xi = x
  89.         LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  90.         LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  91.     WEND
  92.  
  93. 'pete's variation 2019-02-12
  94. SUB FlatEllipseFill1 (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  95.     IF a = 0 OR b = 0 THEN EXIT SUB
  96.     DIM h2 AS _INTEGER64
  97.     DIM w2 AS _INTEGER64
  98.     DIM h2w2 AS _INTEGER64
  99.     DIM yyw2 AS _INTEGER64
  100.     DIM xi AS INTEGER
  101.     DIM dx AS INTEGER
  102.     DIM x AS INTEGER
  103.     DIM y AS INTEGER
  104.     w2 = a * a
  105.     h2 = b * b
  106.     h2w2 = h2 * w2
  107.     xi = a
  108.     dx = 0
  109.     y = 0
  110.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  111.     DO
  112.         y = y + 1
  113.         yyw2 = y * y * w2
  114.         x = xi - dx + 1
  115.         DO
  116.             IF x * x * h2 + yyw2 <= h2w2 THEN EXIT DO
  117.             x = x - 1
  118.         LOOP
  119.         dx = xi - x
  120.         xi = x
  121.         LINE (ox - xi, oy + y)-(ox + xi, oy + y), col, BF
  122.         LINE (ox - xi, oy - y)-(ox + xi, oy - y), col, BF
  123.     LOOP UNTIL y = b
  124.  
  125. 'vince variation on Steve  2019-02-12
  126. SUB FlatEllipseFill2 (x0, y0, rx, ry, c AS _UNSIGNED LONG)
  127.     a = 2 * rx * rx
  128.     b = 2 * ry * ry
  129.  
  130.  
  131.     x = 0
  132.     y = ry
  133.     dx = ry * ry
  134.     dy = rx * rx * (1 - 2 * ry)
  135.     e = 0
  136.     sx = 0
  137.     sy = a * ry
  138.  
  139.     DO WHILE sx <= sy
  140.         LINE (x0 - x, y0 + y)-STEP(2 * x, 0), c, BF
  141.         LINE (x0 - x, y0 - y)-STEP(2 * x, 0), c, BF
  142.  
  143.         x = x + 1
  144.         sx = sx + b
  145.         e = e + dx
  146.         dx = dx + b
  147.  
  148.         IF 2 * e + dy > 0 THEN
  149.             y = y - 1
  150.             sy = sy - a
  151.             e = e + dy
  152.             dy = dy + a
  153.         END IF
  154.     LOOP
  155.  
  156.     x1 = x0 - x
  157.     x2 = x0 + x
  158.     y1 = y0 - y
  159.  
  160.     x = rx
  161.     y = 0
  162.     dx = ry * ry * (1 - 2 * rx)
  163.     dy = rx * rx
  164.     e = 0
  165.     sx = b * rx
  166.     sy = 0
  167.  
  168.     x3 = x0 - x
  169.  
  170.     DO WHILE sx >= sy
  171.         LINE (x0 - x, y0 + y)-(x1, y0 + y), c, BF
  172.         LINE (x0 - x, y0 - y)-(x1, y0 - y), c, BF
  173.         LINE (x0 + x, y0 + y)-(x2, y0 + y), c, BF
  174.         LINE (x0 + x, y0 - y)-(x2, y0 - y), c, BF
  175.  
  176.         y = y + 1
  177.         sy = sy + a
  178.         e = e + dy
  179.         dy = dy + a
  180.  
  181.         IF 2 * e + dx > 0 THEN
  182.             x = x - 1
  183.             sx = sx - b
  184.             e = e + dx
  185.             dx = dx + b
  186.         END IF
  187.     LOOP
  188.  
  189.     LINE (x1, y1)-(x2, y0 + y), c, BF
  190.  
  191.  
  192.  
  193. 'pete's reversion back to SQR   WTH? it's fine time wise!
  194. 'pete's final? 2019-02-12  variation
  195. SUB FlatEllipseFill3 (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  196.     IF a = 0 OR b = 0 THEN EXIT SUB
  197.     DIM h2 AS _INTEGER64
  198.     DIM w2 AS _INTEGER64
  199.     DIM h2w2 AS _INTEGER64
  200.     DIM yyw2 AS _INTEGER64
  201.     DIM x AS INTEGER
  202.     DIM y AS INTEGER
  203.     w2 = a * a
  204.     h2 = b * b
  205.     h2w2 = h2 * w2
  206.     x = a
  207.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  208.     DO
  209.         y = y + 1
  210.         yyw2 = y * y * w2
  211.         x = SQR((h2w2 - yyw2) / h2)
  212.         LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  213.         LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  214.     LOOP UNTIL y = b
  215.  
  216. 'bplus reversion back to SQR  nope over twice the time!
  217. SUB FlatEllipseFill4 (CX AS LONG, CY AS LONG, xRadius AS LONG, yRadius AS LONG, c AS _UNSIGNED LONG)
  218.     DIM scale AS SINGLE, x AS LONG, y AS LONG, xr2 AS LONG
  219.     IF xRadius = 0 OR yRadius = 0 THEN EXIT SUB '<<<<<<<<<<<<< really do need to skip out with 0
  220.     scale = yRadius / xRadius
  221.     LINE (CX, CY - yRadius)-(CX, CY + yRadius), c, BF
  222.     xr2 = xRadius * xRadius
  223.     FOR x = 1 TO xRadius
  224.         y = scale * SQR(xr2 - x * x)
  225.         LINE (CX + x, CY - y)-(CX + x, CY + y), c, BF
  226.         LINE (CX - x, CY - y)-(CX - x, CY + y), c, BF
  227.     NEXT
  228.  
  229.  
  230.  

HA! I see a Y = 0 in circle fill code, maybe we could apply what we have learned to optimize it more. Radius = ABS(R) ???
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 03:15:48 pm
Mark, I tried your test program against my ellipse fill, #3 in your list, and got a better speed test than circle fill...

 [ This attachment cannot be displayed inline in 'Print Page' view ]  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 03:20:44 pm
Dang! what's your system, my tests are running well under 17 secs.

I will try this in 32 bit QB64.

BTW, be sure to run tests with Browser OFF.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 03:25:09 pm
LOL. My kid has the gaming computers. I'm on a $200 laptop that can't keep up with my typing most of the time! :D

OK 3 more tests with browser off. 225 total seconds for 3 runs for mine, 227 total seconds for Circle Fill. Basically a tie of 75 seconds each. Funny that both were slower with the browser off, but with so many things in Windows running in the background, who knows?

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 04:13:28 pm
OK I wrote timings down. This ran allot closer than I expected.
Quote
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      
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 05:04:24 pm
No real speed variance with SQR, pretty cool! Mark, if you wondered why your try at SQR was twice as slow, it was because if used SQR in a loop. Mine just uses it it once per every two lines.

The double draw method Steve submitted is about 20% slower, and the changes Vince made slowed it down about 20% more. Oops. Feel free to challenge that, anyone.

I don't think I want to bother making a hash table form here, but that's where I'd go next to remove SQR from my modification. If we can establish that there is a limit for how wide an ellipse can be, then that's certainly possible. I'm only presuming it would be faster though, I don't know for certain.

I favor the SQR one I came up with, just because it is so simplistic. It would also piss off the C people who posted the other one Bill found, with the inner x loop. Pissing off C people with BASIC just makes me happy!  Oh, if you guys think I'm the only one, check this out, it's hilarious... https://social.microsoft.com/Forums/en-US/ed0e97aa-ea86-49dd-b5b0-01fd41c82cf2/using-com-port-with-qb64

Although... who knows, maybe someone will post some other method that eats our collective lunch. Stay tuned!

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 12, 2019, 05:25:44 pm
Weird, I wasn't aware that I found my function somewhere, because I remember using a whiteboard and the equation of the ellipse to derive my most recent submission. Once a function is simple enough though, it becomes an irreducible mousetrap, and sortof a universal truth. Translation: I bet other smart people derived the same thing, it just *has* to be true. We're too late in computing history to have actually discovered something here.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 06:06:56 pm
https://stackoverflow.com/questions/10322341/simple-algorithm-for-drawing-filled-ellipse-in-c-c

That's why I like to use unique variables, like pete!

Well kudos for grinding it out on your own! I was about half way there, when you posted. After that, I looked around at some stuff on the net and determined I was just heading in the same direction, except that SQR thing was bugging me, so I went on with that after making some tests to see if Steve's find was out of the running. I couldn't see how working on the boob effect would be productive, if the routine ended up being slower, which it is. So on to this single draw system, which looks like the one we will wind up with, unless someone

This is fun stuff, and again kudos. What we need now is either a new method or a way to speed up that SQR calculation in my modification. I wonder how much the internal works grinds out the SQR calculations? It only needs to be rounded as an integer. I mean we could use a square root algorithm to do that, since a hash table is a bit of overkill. It's still a bit tricky to calculate square roots, and requires loops to approximate, even with the "trick" division.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 12, 2019, 06:18:21 pm
Say, there's a mother load of info!

The one with the ascii *-characters in the curved shape is a dead ringer for my method. They even use the same Leibnitz "dx" notation for the tiny increments because this is the same exact setup used to find the area of the ellipse. Calculus is a language after all, you say certain things the same way. Staring at it harder: yikes, do they not have a LINE statement?

I see someone even attempted to do the tilted case but chickened out before arriving at any code. I know exactly why this is, and is why I was so stubborn about solving that issue this week too. The reason? A tilted ellipse does not permit (that I could derive) a strict XY-equation for its position - there's always an extra parameter. After conceding to this, I unleashed the tilted function that takes the punch and uses an extra variable.

At this exact point, I'm not even sure which is the fastest anymore. As the dust settles on this, can anyone (namely Pete or bplus) paste the newest and the greatest below this? Are we going to need a separate function for just circles?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 12, 2019, 11:22:21 pm
Bill: I don't think we need a separate circle routine. As long as the height and the width are the same... BAM, circle. Every bit as fast, too.

The two fastest routines are yours, as modified with different variable types and DO/LOOP replacing FOR/NEXT, and yours with my modifications to substitute SQR for the inner loop. The SQR one is just a tad faster in my tests.

Guys: Do you know in th e last loop x is always zero? That means this routine puts down a horizontal line and dots the top and bottom of any ellipse. I hope that's OK with everyone. Oh, to see what I'm yacking about, here are the numbers...

Code: QB64: [Select]
  1. FOR a = 1 TO 10
  2.     FOR b = 1 TO 10
  3.         CALL p(a, b)
  4.     NEXT
  5.  
  6. SUB p (a, b)
  7. w2 = a * a
  8. h2 = b * b
  9. h2w2 = h2 * w2
  10.     y = y + 1
  11.     yyw2 = y * y * w2
  12.     x = SQR((h2w2 - yyw2) / h2)
  13.     PRINT y; a; b; x; (h2w2 - yyw2) / h2
  14.     SLEEP
  15. LOOP UNTIL y = b
  16. PRINT "============================="
  17.  

I got rid of one more line and a variable in my SQR code. I'll repost it here. What I want to do now is compare it with ellipses of varying size. I also want to make sure I'm getting the same x values as the one that avoids SQR with an inner loop.

Latest SQR code:
Code: QB64: [Select]
  1. SUB FlatEllipseFill5 (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  2. IF a = 0 OR b = 0 THEN EXIT SUB
  3. w2 = a * a
  4. h2 = b * b
  5. h2w2 = h2 * w2
  6. LINE (ox - a, oy)-(ox + a, oy), col, BF
  7. DO WHILE y < b
  8.     y = y + 1
  9.     x = SQR((h2w2 - y * y * w2) / h2)
  10.     LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  11.     LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  12.  

You have to admit, it's pretty freakin' optimized.

Edit: removed unnecessary x = a statement. Thanks Mark!

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 12, 2019, 11:33:30 pm
You don't need x = a either but won't count for much.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 13, 2019, 12:02:29 am
Wow, thanks. I forgot that the single line uses a, not x. Woohoo, another one bites the dust. I'm putting together a test now just to make sure the SQR one does the same size lines as the loop one. I'll let you guys know the results soon.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 13, 2019, 12:25:05 am
Change the division to integer division.  It shaves off about a second on my test runs and still doesn't generate any duplicate lines from my preliminary testing:

Code: QB64: [Select]
  1. SUB FlatEllipseFill6 (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  2.     IF a = 0 OR b = 0 THEN EXIT SUB
  3.     DIM h2 AS _INTEGER64
  4.     DIM w2 AS _INTEGER64
  5.     DIM h2w2 AS _INTEGER64
  6.     DIM x AS INTEGER
  7.     DIM y AS INTEGER
  8.     w2 = a * a
  9.     h2 = b * b
  10.     h2w2 = h2 * w2
  11.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  12.     DO WHILE y < b
  13.         y = y + 1
  14.         x = SQR((h2w2 - y * y * w2) \ h2) ' <<<< HERE
  15.         LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  16.         LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  17.     LOOP
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 13, 2019, 12:31:05 am
And quick question:  What am I missing here; it seems as if this would have to overlap at least one line in an even-lined ellipse height.

Code: QB64: [Select]
  1.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  2.     DO WHILE y < b
  3.         y = y + 1
  4.         x = SQR((h2w2 - y * y * w2) \ h2)
  5.         LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  6.         LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  7.     LOOP

Draw the center line (line 1)...  Then draw above and below it until finished.... (so a 3 line ellipse works, or a 5 line tall ellipse works..)

But when you have an ellipse with a height of 4 lines?  How the heck are we drawing them in odd numbered pairs and then not getting any overlap?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 13, 2019, 01:23:32 am
SQR vs loop method: There is a periodic difference of no more than 1 pixel at various heights of an ellipse. I would attribute that to the different methods, which both use a kind of rounding that is a bit different.

As far as the odd vs even question goes, that's a lot like the last line being a dot. It's the way it's set up to work. If you put in a height of one, if prints one line, but if you put in a height of 2, it prints 3 lines, etc. The good news is it always prints the ellipse on the selected x, y coordinates. If we allow for even lines, then the coordinates are a pixel off in each direction. 

As far as integer division, I tried that a while back, mostly thinking it might take longer as it should involve a rounding step, but when I tried it, I got neck and neck results, so I left it as i. Perhaps Bill and ark can speed check those differences and report back. I'm using QB64 64-bit on a 64-bit Windows 10 but it is a slow system. What Mark can test run in 15 seconds takes me a minute.


Here is a line by line demo...

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(1000, 700, 32)
  2.  
  3. FOR i = 2 TO 300 STEP 2
  4.     CLS
  5.     PRINT "Width = 300 Height ="; i
  6.     FlatEllipseFill5 500, 350, 300, i, _RGBA32(0, 500, 0, 500)
  7.  
  8. SUB FlatEllipseFill5 (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  9. IF a = 0 OR b = 0 THEN EXIT SUB
  10. w2 = a * a
  11. h2 = b * b
  12. h2w2 = h2 * w2
  13. LINE (ox - a, oy)-(ox + a, oy), col, BF
  14. DO WHILE y < b
  15.     y = y + 1
  16.     x = SQR((h2w2 - y * y * w2) / h2)
  17.     col = _RGBA32(y * 50, 100, 500 - y * 50, 300)
  18.     SLEEP
  19.     LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  20.     SLEEP
  21.     LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  22.     SLEEP
  23.  

I wish I knew more about colors to add better contrast. :(

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 13, 2019, 09:32:41 am
Morning,

A quick comment on speed testing... We aren't doing clean experiments all the time. Running the same test multiple times gives varying results, which isn't news... But I'm also finding that the *order* of the tests seems to effect the result. For instance, if I speed test a function against an identical copy of itself, it's rarely a tie: sometimes the function ties itself, but often the function beats itself by a 5%-10% margin, with the second run always being faster than the first. Just pointing this out. Probably a property of doing other stuff with the computer during a test, but that's extremely hard to isolate when stuck in Windows.

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2.  
  3. tt1 = TIMER
  4. FOR k = 1 TO 10000
  5.     CALL FlatEllipseFill(200, 200, 150, 50, _RGBA(100, 100, 100, 100))
  6. tt2 = TIMER
  7. PRINT tt2 - tt1
  8.  
  9. tt3 = TIMER
  10. FOR k = 1 TO 10000
  11.     CALL FlatEllipseFill(250, 250, 150, 50, _RGBA(100, 100, 100, 100))
  12. tt4 = TIMER
  13. PRINT tt4 - tt3
  14.  
  15. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  16.     IF a = 0 OR b = 0 THEN EXIT SUB
  17.     DIM h2 AS _INTEGER64
  18.     DIM w2 AS _INTEGER64
  19.     DIM h2w2 AS _INTEGER64
  20.     DIM x AS INTEGER
  21.     DIM y AS INTEGER
  22.     w2 = a * a
  23.     h2 = b * b
  24.     h2w2 = h2 * w2
  25.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  26.     DO WHILE y < b
  27.         y = y + 1
  28.         x = SQR((h2w2 - y * y * w2) \ h2)
  29.         LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  30.         LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  31.     LOOP

... Despite that, I did find that integer division does seem to perform a little faster on the average than regular division. Everyone agree that the function above is our best contender? I'm itching to lay this one to rest!
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 13, 2019, 10:03:28 am
I am cool with it. Integer division is nice touch Steve! (I say before I test, because I think integer division should be faster because no floating point math needed.)

Append: Oh this is very, very, very odd!
I have pasted the code for sub in reply above to test with Integer division with \ right?!
and after I run the code test, it is switched back to float division / !!! This has happened twice now! First time I thought I copied the wrong thing.

So I am not seeing much improvement on time.

Anyone else getting this?

Append2: never mind, I must have forgotten to save something, the \ is sticking.  But I am not seeing an improvement, maybe because x is already DIM'd as Integer.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 13, 2019, 11:56:16 am
Bill: As to speed testing, I noticed the same things you did. I would swap out tests to offset that. Stupid Windows was preparing an update yesterday, which was messing up things in the background, for instance.

Naming: I wonder how many will fail to realize this puppy makes circles, too? Sure, a circle is just an degenerate ellipse, every community has one, but what else do we have to call it, oval? Hey, how about OVAL FILL? Wait, The Oval Team sounds too much like a 1960s drink option. Oval is more for egg shaped drawings, anyway. Naming things is a real botch sometimes.I like the flatellipsefill name in the current sub calls, except for the possible confusion with... "Well, where's the round ellipse function?"

Other Features: If we threw in a SELECT CASE and an extra parameter, we could include Bill's tilt-a-swirl formula in the non-default case. Zero, the default goes to flat ellipse, while any degree passed goes to CASE ELSE and results in the tilt formula being used. I don't know how much adding SELECT CASE and passing an extra parameter would affect the speed.

Anyway, just some stuff to consider for anyone pressing on...

What I know for sure is after several tests, it doesn't matter how much we try an tweak the one we are concentrating on now, Bill's with modified variable types with loops replacing for/next, and Bill's modified with my SQR replacing the inner loop, both run about the same. That was also true when I added varying sized ellipses to Mark's test program. I thought varying the sizes might show one outperformed but no. The testing, did however, show that Mark's SQR (which he already deduced ran slower), Steve' find, and Vince's modified Steve's find always ran considerably slower. That would probably be even more evident on my machine, because it has a tiny cpu. Hey, it's how it uses it that counts!

I would be for using Bill's modified with or without the SQR modification. What do you guys think about that, the naming, and keeping this just as a "flat" ellipse fill or including a tilt option, if that's OK with Bill? Also, if anyone has any disagreement with my statements, let me have it! I like to provoke thought... my wife says I could leave the thought part off, but you know...

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 13, 2019, 12:15:58 pm
An IF is just as efficient as an SELECT CASE , though personally, I’d prefer separate routines just so the need to pass parameters is minimized.

As for a CircleFill, just have it call the EllipseFill for you.

SUB CircleFill (x, y, r, c)
   EllipseFill x, y, r, r, c
END SUB

Doesn’t get any simpler than that!  ;)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 13, 2019, 01:24:09 pm
I don't like the switch idea for circle or flat ellipse or tilt ellipse but maybe one for fill or no fill?

We do need to complete the set for ellipse for at least tilted ellipse no fill, but I'd like to see flat ellipse outline too, to match the fill version. Using Circle might not match same flat ellipse outline. Another thing to test?

I like Steve's solution for fill circle or fill flat ellipse "switch".
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 13, 2019, 02:24:12 pm
SUB CircleFill (x, y, r, c)
   EllipseFill x, y, r, r, c
END SUB

I lile that idea!

Now, to your other post awhile ago, concerning overlap. I can assure you Bill's routine never overlaps lines, but I'm thinking of omitting the last loop, because it always ends up having x = 0. That means it just places a dot at the top and bottom of the vertical axis, no matter what the width of the ellipse is. I don't think we need that. If eliminated, a value of 1 would yield a line the width of the ellipse, without two stupid 1-pixel dots on the top and the bottom. (Edited in): I had to up the color resolution, but I see there are two lateral dots, too. No Steve, dots, NOT BOOBS! :D I guess this is just inherent in the math but it seems like there should be one more calculation to smooth things out, but then there goes the elegance. The horizontal line could be trimmed by one on each end, no problem.

So as it stands now, a value of 1 yields 3 lines, middle, top, bottom with the formula for the overall height of the flat ellipse as: n * 2 + 1, but if we get rid of the top and bottom "dot" lines, we get one line for a value of one, three lines for a value of two, five lines for a value of 3, and so on.

We either need a way to convey how the sizing works, or change it so it draws the implicit number of lines entered by the user. Changing it would open up a can of worms in the math, that's for sure. :(

So where do we want to head from here? BTW, I can provide some example code, if you don't "see" what I'm talking about.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 13, 2019, 03:48:54 pm
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.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 13, 2019, 03:52:06 pm
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.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 13, 2019, 04:02:17 pm
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
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 13, 2019, 04:08:37 pm
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.

I pick the latter, you can count the radius in pixels up, down, left and right PLUS that seems the convention.

So we are stuck in +1 land, if a radius is n then the pixel count across or up/down is 2n+1.

So Pete should be getting only one dot at top or bottom AND left and right if any partial fractions are always rounded down.

If rounded up when >.5 should occasionally get flat tops and sides of several pixels.


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
Pete,  OK draw the pixel or line then.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 13, 2019, 04:17:53 pm
Try this:

Code: QB64: [Select]
  1.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  2.     DO WHILE y < b
  3.         y = y + 1
  4.         x = SQR((h2w2 - y * y * w2) \ h2 + .5)  '<<<<<<<<<<<<< add .5 for rounding up once and awhile
  5.         LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  6.         LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  7.     LOOP
  8.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 13, 2019, 04:23:21 pm
Or try:

X = _ROUND(SQR(....
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 13, 2019, 04:24:15 pm
If we don't want the dot on top and bottom, we also need to shorten the initial center line. Top and bottom dots go away be just a -1 in the LOOP. We'd have to play around a bit to see if it is as easy to trim that center line.

I don't think I would have noticed this, except I replaced lines with numbers to compare SQR with the loop method, and I noticed the final value for x was always zero. The I increased the brightness of the fill and saw the dots. Bill needs to see if he can live with them, since he worked out the original formula. I'm OK what ever is decided, because no drawings in pixels ever look perfect.

Oh, and I was writing this while you were posting. As for the rounding, I looked into that when I noticed SQR was a bit off by one once in awhile with the loop model, but the drawings were still sound. It was never off by more than one and I think because one is an approximation by trial and error and the other is a math function, it would be pretty hard to match them up all the time, but maybe you got it right there. I'll have to see if I can recover the program I put together to test those values. Stupid Windows updated last night, even though my system was on sleep. It shut down and rebooted, with my permission. That's a "feature" according to assholes (AKA Microsoft developers.)

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 13, 2019, 04:29:36 pm
Oh guys, BTW - This dots "issue" affects both the SQR and non SQR looping method. I think you both realize that, but just in case.

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 13, 2019, 06:20:34 pm
Whoa man, so much to catch up on.

Alright, hope that satisfies a few questions on hand... as for whether we use the SQR version or the inner loop version is an interesting question. As a purist I like the SQR version rather than having a loop within a loop... It's just weird that SQR has been something to avoid in the past but miraculously now it's just as fast. Just weird...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 13, 2019, 07:52:33 pm
Elaborating on the "area" trick...

So we're probably straining at gnats at this point. I came up with a test setup for counting the number of pixels in the ellipse to run it by the expected value. In the code below, I tuned a "fudge factor" to give the correct answer to within 0.08 pixels or so, but this is no reason to get excited. If you simply swap the a- and b- axes (rotate the ellipse 90 degrees), the area should still be the same right? Nope, it's off by 16 pixels for the same exact shape. Right away this tells me that we'll never get the precision we want on a screen without infinite resolution.

Needless to mention, the fudge factor doesn't work for any ellipse besides the test case, so I think our level of pedantic-ness can stop right around here.

Here's my test setup for that:

Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. aaa = 75 ' SWAP THESE TO TEST
  3. bbb = 150
  4.  
  5. CALL FlatEllipseFill(200, 200, aaa, bbb, _RGBA(100, 100, 100, 100))
  6.  
  7. area = 0
  8. FOR i = 1 TO _WIDTH - 1
  9.     FOR j = 1 TO _HEIGHT - 1
  10.         IF POINT(i, j) <> 0 THEN area = area + 1
  11.     NEXT
  12. PRINT area - _PI * aaa * bbb
  13.  
  14. SUB FlatEllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col AS _UNSIGNED LONG)
  15.     IF a = 0 OR b = 0 THEN EXIT SUB
  16.     DIM h2 AS _INTEGER64
  17.     DIM w2 AS _INTEGER64
  18.     DIM h2w2 AS _INTEGER64
  19.     DIM x AS INTEGER
  20.     DIM y AS INTEGER
  21.     w2 = a * a
  22.     h2 = b * b
  23.     h2w2 = h2 * w2
  24.     LINE (ox - a, oy)-(ox + a, oy), col, BF
  25.     DO WHILE y < b
  26.         y = y + 1
  27.         x = SQR((h2w2 - y * y * w2) \ h2) - .45 ' FUDGE FACTOR
  28.         LINE (ox - x, oy + y)-(ox + x, oy + y), col, BF
  29.         LINE (ox - x, oy - y)-(ox + x, oy - y), col, BF
  30.     LOOP
  31.  

In conclusion, after fiddling with this for a second, we should just draw what looks good.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 14, 2019, 09:34:47 am
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]
  1. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  2.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  3.     DIM prc AS _UNSIGNED LONG
  4.     prc = _RGB32(255, 255, 255, 255)
  5.     IF a > b THEN max = a + 1 ELSE max = b + 1
  6.     mx2 = max + max
  7.     tef& = _NEWIMAGE(mx2, mx2)
  8.     _DEST tef&
  9.     _SOURCE tef& 'point wont read without this!
  10.     FOR k = 0 TO 6.2832 + .05 STEP .1
  11.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  12.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  13.         IF k <> 0 THEN
  14.             LINE (lasti, lastj)-(i, j), prc
  15.         ELSE
  16.             PSET (i, j), prc
  17.         END IF
  18.         lasti = i: lastj = j
  19.     NEXT
  20.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  21.     FOR y = 0 TO mx2
  22.         x = 0
  23.         WHILE POINT(x, y) <> prc AND x < mx2
  24.             x = x + 1
  25.         WEND
  26.         xleft(y) = x
  27.         WHILE POINT(x, y) = prc AND x < mx2
  28.             x = x + 1
  29.         WEND
  30.         WHILE POINT(x, y) <> prc AND x < mx2
  31.             x = x + 1
  32.         WEND
  33.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  34.     NEXT
  35.     _DEST destHandle&
  36.     FOR y = 0 TO mx2
  37.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  38.     NEXT
  39.     _FREEIMAGE tef&
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 14, 2019, 10:17:13 am
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]
  1. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  2.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  3.     DIM prc AS _UNSIGNED LONG
  4.     prc = _RGB32(255, 255, 255, 255)
  5.     IF a > b THEN max = a + 1 ELSE max = b + 1
  6.     mx2 = max + max
  7.     tef& = _NEWIMAGE(mx2, mx2)
  8.     _DEST tef&
  9.     _SOURCE tef& 'point wont read without this!
  10.     FOR k = 0 TO 6.2832 + .05 STEP .1
  11.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  12.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  13.         IF k <> 0 THEN
  14.             LINE (lasti, lastj)-(i, j), prc
  15.         ELSE
  16.             PSET (i, j), prc
  17.         END IF
  18.         lasti = i: lastj = j
  19.     NEXT
  20.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  21.     FOR y = 0 TO mx2
  22.         x = 0
  23.         WHILE POINT(x, y) <> prc AND x < mx2
  24.             x = x + 1
  25.         WEND
  26.         xleft(y) = x
  27.         WHILE POINT(x, y) = prc AND x < mx2
  28.             x = x + 1
  29.         WEND
  30.         WHILE POINT(x, y) <> prc AND x < mx2
  31.             x = x + 1
  32.         WEND
  33.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  34.     NEXT
  35.     _DEST destHandle&
  36.     FOR y = 0 TO mx2
  37.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  38.     NEXT
  39.     _FREEIMAGE tef&

Sure it is, and it is vital. Just before drawing the lines this is set in code:
Code: QB64: [Select]
  1.     _DEST destHandle&
The sub works in isolated area to draw the outline and then calc the left and right boundaries of the interior line by line.
It then draws those lines at the destination.

Here is a demo app:
Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse app" ' B+ 2019-02-12
  2.  
  3. CONST xmx = 640
  4. CONST ymx = 640
  5. SCREEN _NEWIMAGE(xmx, ymx, 32)
  6. _SCREENMOVE 340, 40
  7. c = xmx / 2
  8. FOR r = 210 TO 0 STEP -30
  9.     stepper = stepper + 30
  10.     offset = offset - _PI(2 / 24)
  11.     FOR a = 0 TO 2 * _PI - .001 STEP _PI(2 / 12)
  12.         x = c + r * COS(a + offset)
  13.         y = c + r * SIN(a + offset)
  14.         k = _RGBA32(0, 0, 200, 15)
  15.         TiltedEllipseFill 0, x, y, 250 - stepper, stepper, a + offset, k
  16.         _LIMIT 12
  17.     NEXT
  18.  
  19. SUB TiltedEllipseFill (destHandle&, x0, y0, a, b, ang, c AS _UNSIGNED LONG)
  20.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  21.     DIM prc AS _UNSIGNED LONG
  22.     prc = _RGB32(255, 255, 255, 255)
  23.     IF a > b THEN max = a + 1 ELSE max = b + 1
  24.     mx2 = max + max
  25.     tef& = _NEWIMAGE(mx2, mx2)
  26.     _DEST tef&
  27.     _SOURCE tef& 'point wont read without this!
  28.     FOR k = 0 TO 6.2832 + .05 STEP .1
  29.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  30.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  31.         IF k <> 0 THEN
  32.             LINE (lasti, lastj)-(i, j), prc
  33.         ELSE
  34.             PSET (i, j), prc
  35.         END IF
  36.         lasti = i: lastj = j
  37.     NEXT
  38.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  39.     FOR y = 0 TO mx2
  40.         x = 0
  41.         WHILE POINT(x, y) <> prc AND x < mx2
  42.             x = x + 1
  43.         WEND
  44.         xleft(y) = x
  45.         WHILE POINT(x, y) = prc AND x < mx2
  46.             x = x + 1
  47.         WEND
  48.         WHILE POINT(x, y) <> prc AND x < mx2
  49.             x = x + 1
  50.         WEND
  51.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  52.     NEXT
  53.     _DEST destHandle&
  54.     FOR y = 0 TO mx2
  55.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + x0 - max, y + y0 - max)-(xright(y) + x0 - max, y + y0 - max), c, BF
  56.     NEXT
  57.     _FREEIMAGE tef&
  58.  
  59.  
 [ This attachment cannot be displayed inline in 'Print Page' view ]  

After playing around trying to remove Dot at top and bottom, I have decided CircleFill draws a much more pleasing symmetric circle without dots and slightly faster than best FlatEllipseFill. If you try a CIRCLE overlap test over CircleFill you will see overlap all the way around the edge or mostly. If you do a CIRCLE overlap test for FlatEllipseFill, you will see a dotted border overlap all the way around the edge ie not such a good fit. Therefore, CircleFill is staying in my tool box.

You can do FlatEllipse with CIRCLE sub but I doubt the outline would fit our best FlatEllipseFill, therefore FlatEllipseFill will need a partner FlatEllipse sub or a switch to do just the outlines, I favor the latter, one sub with a switch for filling or not.

In my opinion QB64 should be doing these things with Circle as it does with LINE with an "F" switch, THEN all that would be needed is what we have for TiltedEllipse with an tfFill switch.

I wonder what the code for CIRCLE looks like from under-the-hood, how hard would it be to update that?




Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 14, 2019, 10:49:08 am
One thing: It needs to preserve and restore the DEST and SOURCE to pre-execution settings:

Code: QB64: [Select]
  1. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  2.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  3.     DIM prc AS _UNSIGNED LONG
  4.  
  5.     DIM D AS INTEGER, S AS INTEGER 'to preserve old settings
  6.     D = _DEST: S = _SOURCE
  7.  
  8.     prc = _RGB32(255, 255, 255, 255)
  9.     IF a > b THEN max = a + 1 ELSE max = b + 1
  10.     mx2 = max + max
  11.     tef& = _NEWIMAGE(mx2, mx2)
  12.     _DEST tef&
  13.     _SOURCE tef& 'point wont read without this!
  14.     FOR k = 0 TO 6.2832 + .05 STEP .1
  15.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  16.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  17.         IF k <> 0 THEN
  18.             LINE (lasti, lastj)-(i, j), prc
  19.         ELSE
  20.             PSET (i, j), prc
  21.         END IF
  22.         lasti = i: lastj = j
  23.     NEXT
  24.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  25.     FOR y = 0 TO mx2
  26.         x = 0
  27.         WHILE POINT(x, y) <> prc AND x < mx2
  28.             x = x + 1
  29.         WEND
  30.         xleft(y) = x
  31.         WHILE POINT(x, y) = prc AND x < mx2
  32.             x = x + 1
  33.         WEND
  34.         WHILE POINT(x, y) <> prc AND x < mx2
  35.             x = x + 1
  36.         WEND
  37.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  38.     NEXT
  39.     _DEST destHandle&
  40.     FOR y = 0 TO mx2
  41.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  42.     NEXT
  43.     _DEST D: _DEST S 'restore those old settings
  44.     _FREEIMAGE tef&
  45.  


  These lines seem odd to me:

        WHILE POINT(x, y) = prc AND x < mx2
            x = x + 1
        WEND
        WHILE POINT(x, y) <> prc AND x < mx2
            x = x + 1
        WEND

Isn't this a case of WHILE x < mx 2 ??

If POINT(x,y) = prc then we increment x... If POINT(x,y) <> prc then we increment x...  Is there even a need for those checks?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 14, 2019, 11:05:59 am
Crap, you raise an excellent point about having having shapes that are *not* filled. This is super easy to deal with - the reason I exclaim thusly is that nobody raised that idea til now.

EDIT

On second thought, the only shape not inherently "covered" (no pun) in QB64 is the un-filled, tilted ellipse. It covers all the rest.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 14, 2019, 11:23:56 am
Yes, I guess since the sub changes Source and Dest, it does need to be changed back, good catch Steve. I guess I didn't get caught because I never drew anything other than TiltedEllipseFills in my demo.

Steve:
Quote
  These lines seem odd to me:

I am sure they may seem odd to anyone, who hasn't tried drawing the lines at angles = yuck!

In order to have a pretty filled titled ellipse without overlap nor holes, you have to draw either vertical or horizontal lines or if you are really good, draw non overlapping boxes (which I think Vince attempted at one point).

To do this I used STATIC's formula's to draw the ellipse in an isolated area.
Then I went from top to bottom down the y axis and with the help of POINT found the left and right edge of the ellipse along the flat line. This is why the ellipse had to be drawn in an isolated area, so POINT only finds the ellipse points.

With the edges detected along flat lines we can draw a clean,no hole, no overlapping Tilted Ellipse Fill, at the place designated at destHandle&.

This is the code block that is finding the left and right edges of the tilted ellipse drawn in the isolated area:
Code: QB64: [Select]
  1.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  2.     FOR y = 0 TO mx2
  3.         x = 0
  4.         WHILE POINT(x, y) <> prc AND x < mx2
  5.             x = x + 1
  6.         WEND
  7.         xleft(y) = x
  8.         WHILE POINT(x, y) = prc AND x < mx2
  9.             x = x + 1
  10.         WEND
  11.         WHILE POINT(x, y) <> prc AND x < mx2
  12.             x = x + 1
  13.         WEND
  14.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  15.     NEXT
  16.  

You have to find the edges on the same line and you have 3 cases:
1. no edge
2. the left and right edge are the same
3. the left and right edge are different

The added condition
 AND x < mx2
keeps x inside the bounds of the isolated drawing area when one or no POINTs are found.

Finally, when you go to draw the actual lines, you must make sure xLeft(y) is not at the right boundry ie no point of the ellipse was found for that y value.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 14, 2019, 11:38:44 am
A very quick aside:

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. Check out this simple mod that lets you send two colors to the ellipse function, with one color being just for the outline. We won't be keeping this of course:

Code: QB64: [Select]
  1. ' Video settings, Global declarations:
  2.  
  3. SCREEN _NEWIMAGE(800, 600, 32)
  4.  
  5. FOR k = 1 TO 100
  6.     CALL EllipseFill(320, 240, 250, 175, _RGBA(0, 0, 255, 128), _RGBA(0, 255, 0, 128))
  7.  
  8. ' FUNCTIONs and/or SUBs:
  9.  
  10. SUB EllipseFill (ox AS INTEGER, oy AS INTEGER, a AS INTEGER, b AS INTEGER, col1 AS _UNSIGNED LONG, col2 AS _UNSIGNED LONG)
  11.     '  ox  = center x coordinate
  12.     '  oy  = center y coordinate
  13.     '   a  = semimajor axis
  14.     '   b  = semiminor axis
  15.     ' col1 = outline color
  16.     ' col2 = fill color
  17.     IF a = 0 OR b = 0 THEN EXIT SUB
  18.     DIM h2 AS _INTEGER64
  19.     DIM w2 AS _INTEGER64
  20.     DIM h2w2 AS _INTEGER64
  21.     DIM x AS INTEGER
  22.     DIM y AS INTEGER
  23.     w2 = a * a
  24.     h2 = b * b
  25.     h2w2 = h2 * w2
  26.     LINE (ox - a, oy)-(ox + a, oy), col2, BF
  27.     DO WHILE y < b
  28.         y = y + 1
  29.         x = SQR((h2w2 - y * y * w2) \ h2)
  30.         LINE (ox - x, oy + y)-(ox + x, oy + y), col2, BF
  31.         LINE (ox - x, oy - y)-(ox + x, oy - y), col2, BF
  32.     LOOP
  33.     IF col1 <> col2 THEN CIRCLE (ox, oy), a, col1, , , b / a
  34.  

I suppose the a possible 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

EDIT

This will work fastest for the tilted case, as its our only option.

For nontilted things, I guess the challenge is back out there? Oh god...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 14, 2019, 11:51:01 am
Quote
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.

As I recall, we had discovered PAINT is slow and doesn't do alpha... I listed problems of PAINT way back in this thread. This is why  the Tilted Ellipse Fill routine jumps through so many hoops to avoid it!

Again I say, can we do something with QB64 CIRCLE routine ie add fills to what it already does?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 14, 2019, 12:00:27 pm
Quote
Again I say, can we do something with QB64 CIRCLE routine ie add fills to what it already does?

I defer you to [banned user] on that one...
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 14, 2019, 12:24:43 pm
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!

When I need an ellipse fill (and really how often is that?), I will use Titled Ellipse Fill (and no Fill switch?) because that code automatically includes the ability to do Flat Ellipses. This is the one with Steve's S and D fix.

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.

Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 14, 2019, 12:57:54 pm
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.
Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse Fill shape Study" ' B+ 2019-02-14
  2. 'compare to CIRCLE with aspect = a/b
  3.  
  4.  
  5. SCREEN _NEWIMAGE(1000, 700, 32)
  6. _SCREENMOVE 180, 20
  7.  
  8. FOR i = 0 TO 340 'draw ellipse at various heights and compare to CIRCLE with aspect i/300
  9.     CLS
  10.     PRINT "b Radius"; i; "   press any to get to 400, <backspace> to go back one, <esc> for next test."
  11.  
  12.     TiltedEllipseFill 0, 500, 350, 300, i, 0, _RGBA(255, 255, 255, 100)
  13.     IF i <> 0 THEN CIRCLE (500, 350), 300, _RGBA(255, 255, 255, 100), , , i / 300
  14.     k$ = ""
  15.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  16.     IF k$ = CHR$(8) THEN i = i - 2
  17.     IF k$ = CHR$(27) THEN EXIT FOR
  18.  
  19. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  20.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  21.     DIM prc AS _UNSIGNED LONG
  22.  
  23.     DIM D AS INTEGER, S AS INTEGER 'to preserve old settings
  24.     D = _DEST: S = _SOURCE
  25.  
  26.     prc = _RGB32(255, 255, 255, 255)
  27.     IF a > b THEN max = a + 1 ELSE max = b + 1
  28.     mx2 = max + max
  29.     tef& = _NEWIMAGE(mx2, mx2)
  30.     _DEST tef&
  31.     _SOURCE tef& 'point wont read without this!
  32.     FOR k = 0 TO 6.2832 + .05 STEP .1
  33.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  34.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  35.         IF k <> 0 THEN
  36.             LINE (lasti, lastj)-(i, j), prc
  37.         ELSE
  38.             PSET (i, j), prc
  39.         END IF
  40.         lasti = i: lastj = j
  41.     NEXT
  42.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  43.     FOR y = 0 TO mx2
  44.         x = 0
  45.         WHILE POINT(x, y) <> prc AND x < mx2
  46.             x = x + 1
  47.         WEND
  48.         xleft(y) = x
  49.         WHILE POINT(x, y) = prc AND x < mx2
  50.             x = x + 1
  51.         WEND
  52.         WHILE POINT(x, y) <> prc AND x < mx2
  53.             x = x + 1
  54.         WEND
  55.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  56.     NEXT
  57.     _DEST destHandle&
  58.     FOR y = 0 TO mx2
  59.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  60.     NEXT
  61.     _DEST D: _DEST S 'restore those old settings
  62.     _FREEIMAGE tef&
  63.  
  64.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 14, 2019, 01:09:49 pm
I have to read the previous post in the reflection of a funhouse mirror to make sense of it...

Quote
OK maybe one of these days I will dig into the Source Code...

Here's what you do. Find every instance of CIRCLE in the qb64 source code, and make a copy of it - CIRCLE2 or whatever. As soon as you can use CIRCLE2 to completely replace circle, you're ready to do the filling and rename CIRCLE2 to whatever. If successful, the result will be your occult object and not much more unfortunately, it was decided long ago that we won't add this kind of stuff to the language itself until someone clearly and intelligently defines when to stop. That has never occurred and I doubt it will.

Quote
In meantime, I am keeping CircleFill in my tool box...

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.

Quote
...and IMO it should go in the forum's as the number 1 entry!

If the Librarian can figure out how to arrange posts alphabetically instead of by date, you may have your wish on this until an A- or B- named function claims the #1 spot.

Quote
If I really need speedier Flat Ellipses then STATIC's fudge of Pete's variation will do fine!

Something tells me you swapped the names here, but who's keeping track? Authors/contributors/useful testers will be credited in alphabetical order in the Toolbox forum. Whoever wants to do the research can click the link to this thread any they can see who worked on what.

Quote
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.

That's a great issue. I prefer our tooling stay as pure as possible, i.e. avoiding anything that brings in complexity with underscore commands, image handles, and all that, so long as it does the best job. (Just a weird preference.) Since unfilled ellipses are just PSET and LINE, I'm all about having two functions, one for filled, one for unfilled.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 14, 2019, 01:12:57 pm
Quote
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.

Are you knocking down straw men intentionally, or just need some coffee?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 14, 2019, 02:06:42 pm
Quote
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.

Are you knocking down straw men intentionally, or just need some coffee?

I could use some more sleep but I am seeing with the comparison code that CIRCLE must be drawing ellipse (using aspect) with an entirely different method than any discussed here ie pretty good overlap on left side, complete miss on right.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: SMcNeill on February 14, 2019, 02:53:17 pm
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.)

From memory, first section of code is declarations, followed by boundary checks (make certain the circle is being drawn inside the viewports), followed by the actual plotting routine at the end.

One thing to keep in mind: Circle also plots arcs; not just circles.  To adapt the existing code to a fill routine, you’d basically need to plot lines inside that arc routine.

Which, really, I wouldn’t mind seeing a fast arc fill routine to boot.  ;)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 14, 2019, 10:57:53 pm
B+
Quote
In meantime, I am keeping CircleFill in my tool box...
STATIC
Quote
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.

Code: QB64: [Select]
  1. 'from Steve Gold standard
  2. SUB fcirc0 (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  3.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  4.     DIM X AS INTEGER, Y AS INTEGER
  5.  
  6.     Radius = ABS(R)
  7.     RadiusError = -Radius
  8.     X = Radius
  9.     Y = 0
  10.  
  11.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  12.  
  13.     ' Draw the middle span here so we don't draw it twice in the main loop,
  14.     ' which would be a problem with blending turned on.
  15.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  16.  
  17.     WHILE X > Y
  18.         RadiusError = RadiusError + Y * 2 + 1
  19.         IF RadiusError >= 0 THEN
  20.             IF X <> Y + 1 THEN
  21.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  22.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  23.             END IF
  24.             X = X - 1
  25.             RadiusError = RadiusError - X * 2
  26.         END IF
  27.         Y = Y + 1
  28.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  29.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  30.     WEND
  31.  
  32.  

Here is consolidation of speed tests with other Circle Fills tried:
Code: QB64: [Select]
  1. _TITLE "Circle Fill speed tests"
  2. SCREEN _NEWIMAGE(1220, 680, 32)
  3. _SCREENMOVE 100, 20
  4. ntests = 100000 'it takes a really long run to prove Gold Standard Speed 167.9 versus vince 168.1
  5. ntests = 1000 'fast elimination
  6.  
  7. 'It has been noticed that the one going first has a disadvantage
  8.  
  9. start## = TIMER 'this runs the Gold standard to beat  on Right Side of screen
  10. FOR i = 1 TO ntests
  11.     fcirc0 915, 305, 300, _RGBA32(0, 100, 0, 100)
  12. finish## = TIMER - start##
  13. _PRINTSTRING (700, 615), "Time for" + STR$(ntests) + " Gold Standard Circle Fills:" + STR$(finish##)
  14.  
  15. ' ==================================================== the contender on left of screen
  16.  
  17. start## = TIMER
  18. FOR i = 1 TO ntests
  19.     fCirc4 305, 305, 300, _RGBA32(0, 100, 0, 100)
  20. finish## = TIMER - start##
  21. _PRINTSTRING (100, 615), "Time for" + STR$(ntests) + " Contender Fills:" + STR$(finish##)
  22.  
  23. 'from Steve Gold standard
  24. SUB fcirc0 (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  25.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  26.     DIM X AS INTEGER, Y AS INTEGER
  27.  
  28.     Radius = ABS(R)
  29.     RadiusError = -Radius
  30.     X = Radius
  31.     Y = 0
  32.  
  33.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  34.  
  35.     ' Draw the middle span here so we don't draw it twice in the main loop,
  36.     ' which would be a problem with blending turned on.
  37.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  38.  
  39.     WHILE X > Y
  40.         RadiusError = RadiusError + Y * 2 + 1
  41.         IF RadiusError >= 0 THEN
  42.             IF X <> Y + 1 THEN
  43.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  44.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  45.             END IF
  46.             X = X - 1
  47.             RadiusError = RadiusError - X * 2
  48.         END IF
  49.         Y = Y + 1
  50.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  51.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  52.     WEND
  53.  
  54.  
  55.  
  56. 'vince's circle fill   this one does not bother with types good almost identical to Steve's
  57. SUB fcirc1 (x, y, r, c AS _UNSIGNED LONG)
  58.     x0 = r
  59.     y0 = 0
  60.     e = -r
  61.     DO WHILE y0 < x0
  62.         IF e <= 0 THEN
  63.             y0 = y0 + 1
  64.             LINE (x - x0, y + y0)-(x + x0, y + y0), c, BF
  65.             LINE (x - x0, y - y0)-(x + x0, y - y0), c, BF
  66.             e = e + 2 * y0
  67.         ELSE
  68.             LINE (x - y0, y - x0)-(x + y0, y - x0), c, BF
  69.             LINE (x - y0, y + x0)-(x + y0, y + x0), c, BF
  70.             x0 = x0 - 1
  71.             e = e - 2 * x0
  72.         END IF
  73.     LOOP
  74.     LINE (x - r, y)-(x + r, y), c, BF
  75.  
  76. 'this does not overlap with circle well 2.13 x's Gold Time
  77. SUB fCirc2 (xx AS LONG, yy AS LONG, r AS LONG, K AS _UNSIGNED LONG)
  78.     DIM r2 AS LONG, x AS LONG, y AS LONG, xstop AS LONG
  79.     r2 = r * r
  80.     x = 1
  81.     xstop = r + 1
  82.     WHILE x < xstop 'remove FOR loop
  83.         y = SQR(r2 - x * x)
  84.         LINE (xx - x, yy + y)-(xx - x, yy - y), K, BF
  85.         LINE (xx + x, yy + y)-(xx + x, yy - y), K, BF
  86.         x = x + 1
  87.     WEND
  88.     LINE (xx, yy - r)-(xx, yy + r), K, BF
  89.  
  90. 'andy amaya's version from SB, way too much overlapping!   Junk as is but 1.1 Gold Standard Time
  91. SUB fCirc3 (CX AS LONG, CY AS LONG, R AS LONG, K AS _UNSIGNED LONG) 'thanks Andy Amaya for heads up
  92.     DIM x AS LONG, y AS LONG, Xchange AS INTEGER, yChange AS INTEGER, RadiusError AS INTEGER
  93.     x = R
  94.     y = 0
  95.     Xchange = 1 - 2 * R
  96.     yChange = 1
  97.     RadiusError = 0
  98.  
  99.     WHILE x >= y
  100.         LINE (CX - x, CY + y)-(CX + x, CY + y), K, BF ';used calc'd values to draw
  101.         LINE (CX - x, CY - y)-(CX + x, CY - y), K, BF ';scan lines from points
  102.         LINE (CX - y, CY + x)-(CX + y, CY + x), K, BF ';in opposite octants
  103.         LINE (CX - y, CY - x)-(CX + y, CY - x), K, BF
  104.         y = y + 1
  105.         RadiusError = RadiusError + yChange
  106.         yChange = yChange + 2
  107.  
  108.         IF 2 * RadiusError + Xchange > 0 THEN
  109.             x = x - 1
  110.             RadiusError = RadiusError + Xchange
  111.             Xchange = Xchange + 2
  112.         END IF
  113.     WEND
  114.  
  115. 'fCirc but doing octants until get to square, then just do square fill! 1.18 Gold Sdt
  116. 'this is closer to matching the Gold Standard
  117. SUB fCirc4 (xx AS LONG, yy AS LONG, r AS LONG, K AS _UNSIGNED LONG)
  118.     DIM r2 AS LONG, t AS LONG, dist AS LONG, tstop AS LONG
  119.     r2 = r * r
  120.     t = r 'r - 1 gets rid of nipples but...
  121.     tstop = r * .707106781
  122.     WHILE t > tstop 'remove FOR loop
  123.         dist = SQR(r2 - t * t) ' + .5 for rounding down
  124.         LINE (xx - t, yy + dist)-(xx - t, yy - dist), K, BF
  125.         LINE (xx + t, yy + dist)-(xx + t, yy - dist), K, BF
  126.         LINE (xx + dist, yy + t)-(xx - dist, yy + t), K, BF
  127.         LINE (xx + dist, yy - t)-(xx - dist, yy - t), K, BF
  128.         t = t - 1
  129.     WEND
  130.     LINE (xx - tstop, yy - tstop)-(xx + tstop, yy + tstop), K, BF
  131.  
  132. 'add a routine for sqr root   1,16 X's Gold Std
  133. SUB fCirc5 (xx AS LONG, yy AS LONG, r AS LONG, K AS _UNSIGNED LONG)
  134.     DIM r2 AS LONG, t AS LONG, tstop AS LONG
  135.     DIM dist1 AS SINGLE, dist AS SINGLE, dist2 AS LONG, s AS LONG
  136.     r2 = r * r
  137.     t = r 'r - 1 gets rid of nipples but...
  138.     tstop = r * .707106781
  139.     WHILE t > tstop 'remove FOR loop
  140.  
  141.         'VVVVVVVVVVVVVVVVVVV this might now save a shade off SQR
  142.         s = r2 - t * t
  143.         dist = s / 10
  144.         dist2 = dist * dist
  145.         'WHILE ABS(dist ^ 2 - s) >= 1  'no! avoid function calls!
  146.         WHILE dist2 - s > 1 OR dist2 - s < -1
  147.             dist = .5 * (dist + s / dist)
  148.             dist2 = dist * dist
  149.         WEND
  150.  
  151.         'VVVVVVVVVVVVVVVVV  faster to use this YES
  152.         'dist = SQR(r2 - t * t) ' + .5 for rounding down
  153.  
  154.  
  155.         LINE (xx - t, yy + dist)-(xx - t, yy - dist), K, BF
  156.         LINE (xx + t, yy + dist)-(xx + t, yy - dist), K, BF
  157.         LINE (xx + dist, yy + t)-(xx - dist, yy + t), K, BF
  158.         LINE (xx + dist, yy - t)-(xx - dist, yy - t), K, BF
  159.         t = t - 1
  160.     WEND
  161.     LINE (xx - tstop, yy - tstop)-(xx + tstop, yy + tstop), K, BF
  162.  
  163. 'too slow, dest can't just be 0  Junk as is
  164. SUB fcirc6 (xOrigin AS LONG, yOrigin AS LONG, radius AS LONG, K AS _UNSIGNED LONG)
  165.     a& = _NEWIMAGE(1, 1, 32)
  166.     _DEST a&
  167.     PSET (0, 0), K
  168.     _DEST 0
  169.     DIM x1 AS LONG, y1 AS LONG, x2 AS LONG, y2 AS LONG, i AS INTEGER
  170.     DIM polyAngle AS SINGLE
  171.     polyAngle = _PI(2) / 60
  172.     x1 = xOrigin + radius * COS(polyAngle)
  173.     y1 = yOrigin + radius * SIN(polyAngle)
  174.     FOR i = 2 TO 61
  175.         x2 = xOrigin + radius * COS(i * polyAngle)
  176.         y2 = yOrigin + radius * SIN(i * polyAngle)
  177.         _MAPTRIANGLE (0, 0)-(0, 0)-(0, 0), a& TO(xOrigin, yOrigin)-(x1, y1)-(x2, y2), 0
  178.         x1 = x2: y1 = y2
  179.     NEXT
  180.     _FREEIMAGE a& '<<< this is important!
  181.  

Here is consolidation of size and overlap with circle tests (checking for nipples, or dots... BTW discovered from these tests, the CIRCLE sub overlaps itself at 0, 90, 180, 270 degrees!):
Code: QB64: [Select]
  1. _TITLE "CircleFill Overlap test"
  2. SCREEN _NEWIMAGE(1000, 700, 32)
  3. _SCREENMOVE 180, 20
  4. 'B+ 2019-02-10 resave this code to
  5. 'just test this code for proper filling without overlap, timed tests are else where
  6.  
  7. FOR i = 0 TO 200 'draw circle at various radii
  8.     CLS
  9.     PRINT "Radius"; i; "   press any to add until get to 200, <backspace> to go back one, <esc> for next test."
  10.     'CIRCLE (500, 350), i, _RGBA(255, 255, 255, 40)
  11.     fcirc6 500, 350, i, _RGBA(255, 255, 255, 100)
  12.     k$ = ""
  13.     WHILE LEN(k$) = 0: k$ = INKEY$: WEND
  14.     IF k$ = CHR$(8) THEN i = i - 2
  15.     IF k$ = CHR$(27) THEN EXIT FOR
  16.  
  17. 'from Steve Gold standard
  18. SUB fcirc0 (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  19.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  20.     DIM X AS INTEGER, Y AS INTEGER
  21.  
  22.     Radius = ABS(R)
  23.     RadiusError = -Radius
  24.     X = Radius
  25.     Y = 0
  26.  
  27.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  28.  
  29.     ' Draw the middle span here so we don't draw it twice in the main loop,
  30.     ' which would be a problem with blending turned on.
  31.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  32.  
  33.     WHILE X > Y
  34.         RadiusError = RadiusError + Y * 2 + 1
  35.         IF RadiusError >= 0 THEN
  36.             IF X <> Y + 1 THEN
  37.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  38.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  39.             END IF
  40.             X = X - 1
  41.             RadiusError = RadiusError - X * 2
  42.         END IF
  43.         Y = Y + 1
  44.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  45.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  46.     WEND
  47.  
  48.  
  49.  
  50. 'vince's circle fill   this one does not bother with types good almost identical to Steve's
  51. SUB fcirc1 (x, y, r, c AS _UNSIGNED LONG)
  52.     x0 = r
  53.     y0 = 0
  54.     e = -r
  55.     DO WHILE y0 < x0
  56.         IF e <= 0 THEN
  57.             y0 = y0 + 1
  58.             LINE (x - x0, y + y0)-(x + x0, y + y0), c, BF
  59.             LINE (x - x0, y - y0)-(x + x0, y - y0), c, BF
  60.             e = e + 2 * y0
  61.         ELSE
  62.             LINE (x - y0, y - x0)-(x + y0, y - x0), c, BF
  63.             LINE (x - y0, y + x0)-(x + y0, y + x0), c, BF
  64.             x0 = x0 - 1
  65.             e = e - 2 * x0
  66.         END IF
  67.     LOOP
  68.     LINE (x - r, y)-(x + r, y), c, BF
  69.  
  70. 'this does not overlap with circle well
  71. SUB fCirc2 (xx AS LONG, yy AS LONG, r AS LONG, K AS _UNSIGNED LONG)
  72.     DIM r2 AS LONG, x AS LONG, y AS LONG, xstop AS LONG
  73.     r2 = r * r
  74.     x = 1
  75.     xstop = r + 1
  76.     WHILE x < xstop 'remove FOR loop
  77.         y = SQR(r2 - x * x)
  78.         LINE (xx - x, yy + y)-(xx - x, yy - y), K, BF
  79.         LINE (xx + x, yy + y)-(xx + x, yy - y), K, BF
  80.         x = x + 1
  81.     WEND
  82.     LINE (xx, yy - r)-(xx, yy + r), K, BF
  83.  
  84. 'andy amaya's version from SB, way too much overlapping!   Junk as is
  85. SUB fCirc3 (CX AS LONG, CY AS LONG, R AS LONG, K AS _UNSIGNED LONG) 'thanks Andy Amaya for heads up
  86.     DIM x AS LONG, y AS LONG, Xchange AS INTEGER, yChange AS INTEGER, RadiusError AS INTEGER
  87.     x = R
  88.     y = 0
  89.     Xchange = 1 - 2 * R
  90.     yChange = 1
  91.     RadiusError = 0
  92.  
  93.     WHILE x >= y
  94.         LINE (CX - x, CY + y)-(CX + x, CY + y), K, BF ';used calc'd values to draw
  95.         LINE (CX - x, CY - y)-(CX + x, CY - y), K, BF ';scan lines from points
  96.         LINE (CX - y, CY + x)-(CX + y, CY + x), K, BF ';in opposite octants
  97.         LINE (CX - y, CY - x)-(CX + y, CY - x), K, BF
  98.         y = y + 1
  99.         RadiusError = RadiusError + yChange
  100.         yChange = yChange + 2
  101.  
  102.         IF 2 * RadiusError + Xchange > 0 THEN
  103.             x = x - 1
  104.             RadiusError = RadiusError + Xchange
  105.             Xchange = Xchange + 2
  106.         END IF
  107.     WEND
  108.  
  109. 'fCirc but doing octants until get to square, then just do square fill!
  110. 'this is closer to matching the Gold Standard
  111. SUB fCirc4 (xx AS LONG, yy AS LONG, r AS LONG, K AS _UNSIGNED LONG)
  112.     DIM r2 AS LONG, t AS LONG, dist AS LONG, tstop AS LONG
  113.     r2 = r * r
  114.     t = r 'r - 1 gets rid of nipples but...
  115.     tstop = r * .707106781
  116.     WHILE t > tstop 'remove FOR loop
  117.         dist = SQR(r2 - t * t) ' + .5 for rounding down
  118.         LINE (xx - t, yy + dist)-(xx - t, yy - dist), K, BF
  119.         LINE (xx + t, yy + dist)-(xx + t, yy - dist), K, BF
  120.         LINE (xx + dist, yy + t)-(xx - dist, yy + t), K, BF
  121.         LINE (xx + dist, yy - t)-(xx - dist, yy - t), K, BF
  122.         t = t - 1
  123.     WEND
  124.     LINE (xx - tstop, yy - tstop)-(xx + tstop, yy + tstop), K, BF
  125.  
  126. 'add a routine for sqr root
  127. SUB fCirc5 (xx AS LONG, yy AS LONG, r AS LONG, K AS _UNSIGNED LONG)
  128.     DIM r2 AS LONG, t AS LONG, tstop AS LONG
  129.     DIM dist1 AS SINGLE, dist AS SINGLE, dist2 AS LONG, s AS LONG
  130.     r2 = r * r
  131.     t = r 'r - 1 gets rid of nipples but...
  132.     tstop = r * .707106781
  133.     WHILE t > tstop 'remove FOR loop
  134.  
  135.         'VVVVVVVVVVVVVVVVVVV this might now save a shade off SQR
  136.         s = r2 - t * t
  137.         dist = s / 10
  138.         dist2 = dist * dist
  139.         'WHILE ABS(dist ^ 2 - s) >= 1  'no! avoid function calls!
  140.         WHILE dist2 - s > 1 OR dist2 - s < -1
  141.             dist = .5 * (dist + s / dist)
  142.             dist2 = dist * dist
  143.         WEND
  144.  
  145.         'VVVVVVVVVVVVVVVVV  faster to use this YES
  146.         'dist = SQR(r2 - t * t) ' + .5 for rounding down
  147.  
  148.  
  149.         LINE (xx - t, yy + dist)-(xx - t, yy - dist), K, BF
  150.         LINE (xx + t, yy + dist)-(xx + t, yy - dist), K, BF
  151.         LINE (xx + dist, yy + t)-(xx - dist, yy + t), K, BF
  152.         LINE (xx + dist, yy - t)-(xx - dist, yy - t), K, BF
  153.         t = t - 1
  154.     WEND
  155.     LINE (xx - tstop, yy - tstop)-(xx + tstop, yy + tstop), K, BF
  156.  
  157. 'terrible overlap too slow, dest can't just be 0  Junk as is
  158. SUB fcirc6 (xOrigin AS LONG, yOrigin AS LONG, radius AS LONG, K AS _UNSIGNED LONG)
  159.     a& = _NEWIMAGE(1, 1, 32)
  160.     _DEST a&
  161.     PSET (0, 0), K
  162.     _DEST 0
  163.     DIM x1 AS LONG, y1 AS LONG, x2 AS LONG, y2 AS LONG, i AS INTEGER
  164.     DIM polyAngle AS SINGLE
  165.     polyAngle = _PI(2) / 60
  166.     x1 = xOrigin + radius * COS(polyAngle)
  167.     y1 = yOrigin + radius * SIN(polyAngle)
  168.     FOR i = 2 TO 61
  169.         x2 = xOrigin + radius * COS(i * polyAngle)
  170.         y2 = yOrigin + radius * SIN(i * polyAngle)
  171.         _MAPTRIANGLE (0, 0)-(0, 0)-(0, 0), a& TO(xOrigin, yOrigin)-(x1, y1)-(x2, y2), 0
  172.         x1 = x2: y1 = y2
  173.     NEXT
  174.     _FREEIMAGE a& '<<< this is important!
  175.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 15, 2019, 12:08:10 am
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?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 15, 2019, 10:12:34 am
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?

NO! I am saying THE QB64 CIRCLE function is overlapping itself at the named angles.

Here is a demo that makes it clear as a bell:
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. _SCREENMOVE 250, 60
  3. FOR r = 0 TO 250
  4.     CIRCLE (400, 300), r, _RGBA(255, 255, 255, 100)
  5.  

 
 

Quote
I swear I wanted to lay this thing to rest like 5 pages ago...

Voltaire — 'The secret of being a bore is to tell everything.'

The Gold Standard is even better than THE QB64 CIRCLE sub in this respect!
Code: QB64: [Select]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2. _SCREENMOVE 250, 60
  3. FOR r = 250 TO 0 STEP -60
  4.     fcirc 400, 300, r, _RGBA(255, 255, 255, 100)
  5. 'from Steve Gold standard
  6. SUB fcirc (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  7.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  8.     DIM X AS INTEGER, Y AS INTEGER
  9.  
  10.     Radius = ABS(R)
  11.     RadiusError = -Radius
  12.     X = Radius
  13.     Y = 0
  14.  
  15.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  16.  
  17.     ' Draw the middle span here so we don't draw it twice in the main loop,
  18.     ' which would be a problem with blending turned on.
  19.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  20.  
  21.     WHILE X > Y
  22.         RadiusError = RadiusError + Y * 2 + 1
  23.         IF RadiusError >= 0 THEN
  24.             IF X <> Y + 1 THEN
  25.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  26.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  27.             END IF
  28.             X = X - 1
  29.             RadiusError = RadiusError - X * 2
  30.         END IF
  31.         Y = Y + 1
  32.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  33.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  34.     WEND
  35.  
  36.  

 

Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 15, 2019, 10:46:17 am
Steve:
Quote
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.)

Thanks Steve, found it and see why no one wants to mess with it! Yeeou-sa! It seems it's main concern is handling the arcs, and yet we still have to fix the arcs if we want to PAINT pie slices with it.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: _vince on February 15, 2019, 11:02:04 am
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?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 15, 2019, 11:34:05 am
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.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 15, 2019, 12:08:21 pm
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?

My guess after peeking into the qblib.cpp file, circle sub, that they are using Double Precision and Gold Standard is using Integers and the LINE sub rounds things it's own way. :)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 15, 2019, 12:14:01 pm
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.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: FellippeHeitor on February 15, 2019, 01:02:31 pm
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.

One question I haven't seen asked here yet (I just skimmed, may have missed it) is: Did QB4.5 do the same? If the odd behavior was already there, then CIRCLE should remain "buggy" concerning those middle lines.

That wouldn't prevent a new circle implementation to be added.

Not adding a new _CIRCLE command - that would be ridiculous -, but adding a new switch to the old existing CIRCLE command sounds feasible - one for the filled version, maybe another for an anti-aliased alternative routine that doesn't contain the vice of yore, what have you.

Who's willing to get their hands dirty with c code?
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: FellippeHeitor on February 15, 2019, 01:06:52 pm
Looking at the sample code provided, I take back my "did the bug already exist" question. It's using semi-transparent color, something not existing in QB4.5.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 16, 2019, 01:41:18 am
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]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2.  
  3. DIM TransRed AS _UNSIGNED LONG
  4. DIM TransGreen AS _UNSIGNED LONG
  5. DIM TransBlue AS _UNSIGNED LONG
  6. TransRed = _RGBA(255, 0, 0, 128)
  7. TransGreen = _RGBA(0, 255, 0, 128)
  8. TransBlue = _RGBA(0, 0, 255, 128)
  9.  
  10. CALL CircleFill(100, 100, 75, TransRed)
  11. CALL CircleFill(120, 120, 75, TransBlue)
  12.  
  13. CALL EllipseFill(550, 100, 150, 75, TransBlue)
  14. CALL EllipseFill(570, 120, 150, 75, TransGreen)
  15.  
  16. CALL EllipseTiltFill(0, 350, 400, 150, 75, 3.14 / 6, TransGreen)
  17. CALL EllipseTiltFill(0, 370, 420, 150, 75, 3.14 / 4, TransRed)
  18.  
  19.  
  20. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  21.     ' CX = center x coordinate
  22.     ' CY = center y coordinate
  23.     '  R = radius
  24.     '  C = fill color
  25.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  26.     DIM X AS INTEGER, Y AS INTEGER
  27.     Radius = ABS(R)
  28.     RadiusError = -Radius
  29.     X = Radius
  30.     Y = 0
  31.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  32.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  33.     WHILE X > Y
  34.         RadiusError = RadiusError + Y * 2 + 1
  35.         IF RadiusError >= 0 THEN
  36.             IF X <> Y + 1 THEN
  37.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  38.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  39.             END IF
  40.             X = X - 1
  41.             RadiusError = RadiusError - X * 2
  42.         END IF
  43.         Y = Y + 1
  44.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  45.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  46.     WEND
  47.  
  48. SUB EllipseFill (CX AS INTEGER, CY AS INTEGER, a AS INTEGER, b AS INTEGER, C AS _UNSIGNED LONG)
  49.     ' CX = center x coordinate
  50.     ' CY = center y coordinate
  51.     '  a = semimajor axis
  52.     '  b = semiminor axis
  53.     '  C = fill color
  54.     IF a = 0 OR b = 0 THEN EXIT SUB
  55.     DIM h2 AS _INTEGER64
  56.     DIM w2 AS _INTEGER64
  57.     DIM h2w2 AS _INTEGER64
  58.     DIM x AS INTEGER
  59.     DIM y AS INTEGER
  60.     w2 = a * a
  61.     h2 = b * b
  62.     h2w2 = h2 * w2
  63.     LINE (CX - a, CY)-(CX + a, CY), C, BF
  64.     DO WHILE y < b
  65.         y = y + 1
  66.         x = SQR((h2w2 - y * y * w2) \ h2)
  67.         LINE (CX - x, CY + y)-(CX + x, CY + y), C, BF
  68.         LINE (CX - x, CY - y)-(CX + x, CY - y), C, BF
  69.     LOOP
  70.  
  71. SUB EllipseTiltFill (destHandle&, CX, CY, a, b, ang, C AS _UNSIGNED LONG)
  72.     '  destHandle& = destination handle
  73.     '  CX = center x coordinate
  74.     '  CY = center y coordinate
  75.     '   a = semimajor axis
  76.     '   b = semiminor axis
  77.     ' ang = clockwise orientation of semimajor axis in radians (0 default)
  78.     '   C = fill color
  79.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  80.     DIM prc AS _UNSIGNED LONG
  81.     DIM D AS INTEGER, S AS INTEGER
  82.     D = _DEST: S = _SOURCE
  83.     prc = _RGB32(255, 255, 255, 255)
  84.     IF a > b THEN max = a + 1 ELSE max = b + 1
  85.     mx2 = max + max
  86.     tef& = _NEWIMAGE(mx2, mx2)
  87.     _DEST tef&
  88.     _SOURCE tef&
  89.     FOR k = 0 TO 6.283185307179586 + .025 STEP .025
  90.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  91.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  92.         IF k <> 0 THEN
  93.             LINE (lasti, lastj)-(i, j), prc
  94.         ELSE
  95.             PSET (i, j), prc
  96.         END IF
  97.         lasti = i: lastj = j
  98.     NEXT
  99.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  100.     FOR y = 0 TO mx2
  101.         x = 0
  102.         WHILE POINT(x, y) <> prc AND x < mx2
  103.             x = x + 1
  104.         WEND
  105.         xleft(y) = x
  106.         WHILE POINT(x, y) = prc AND x < mx2
  107.             x = x + 1
  108.         WEND
  109.         WHILE POINT(x, y) <> prc AND x < mx2
  110.             x = x + 1
  111.         WEND
  112.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  113.     NEXT
  114.     _DEST destHandle&
  115.     FOR y = 0 TO mx2
  116.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + CX - max, y + CY - max)-(xright(y) + CX - max, y + CY - max), C, BF
  117.     NEXT
  118.     _DEST D: _DEST S
  119.     _FREEIMAGE tef&
  120.  
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: Pete on February 16, 2019, 03:56:10 am
Ironic Bill, if you used your real name, you'd receive top bill-ing. Oh well, if B-Plus gets his grades up next semester, we're all screwed! And no Steve, I'm not modifying my name to A-Peter. :D

Wow, who'd ah thunk this project would have us going around in circles? I guess we all should have seen that one coming. Well now that's it's over, I'd have to say it's been a blast. It's the second group project I've taken part in over 25 years and amazingly enough, both times everybody got along really well from start to finish. You guys rock and thinks for letting me participate!

Pete
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 16, 2019, 09:40:27 am
Bumping this topic, hopefully for the last time (by me - anyone else is invited to speak up about whatever crosses their mind).

https://www.qb64.org/forum/index.php?topic=1069.msg102619 (https://www.qb64.org/forum/index.php?topic=1069.msg102619)
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 16, 2019, 09:52:04 am
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]
  1. SCREEN _NEWIMAGE(800, 600, 32)
  2.  
  3. DIM TransRed AS _UNSIGNED LONG
  4. DIM TransGreen AS _UNSIGNED LONG
  5. DIM TransBlue AS _UNSIGNED LONG
  6. TransRed = _RGBA(255, 0, 0, 128)
  7. TransGreen = _RGBA(0, 255, 0, 128)
  8. TransBlue = _RGBA(0, 0, 255, 128)
  9.  
  10. CALL CircleFill(100, 100, 75, TransRed)
  11. CALL CircleFill(120, 120, 75, TransBlue)
  12.  
  13. CALL EllipseFill(550, 100, 150, 75, TransBlue)
  14. CALL EllipseFill(570, 120, 150, 75, TransGreen)
  15.  
  16. CALL EllipseTiltFill(0, 350, 400, 150, 75, 3.14 / 6, TransGreen)
  17. CALL EllipseTiltFill(0, 370, 420, 150, 75, 3.14 / 4, TransRed)
  18.  
  19.  
  20. SUB CircleFill (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  21.     ' CX = center x coordinate
  22.     ' CY = center y coordinate
  23.     '  R = radius
  24.     '  C = fill color
  25.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  26.     DIM X AS INTEGER, Y AS INTEGER
  27.     Radius = ABS(R)
  28.     RadiusError = -Radius
  29.     X = Radius
  30.     Y = 0
  31.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  32.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  33.     WHILE X > Y
  34.         RadiusError = RadiusError + Y * 2 + 1
  35.         IF RadiusError >= 0 THEN
  36.             IF X <> Y + 1 THEN
  37.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  38.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  39.             END IF
  40.             X = X - 1
  41.             RadiusError = RadiusError - X * 2
  42.         END IF
  43.         Y = Y + 1
  44.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  45.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  46.     WEND
  47.  
  48. SUB EllipseFill (CX AS INTEGER, CY AS INTEGER, a AS INTEGER, b AS INTEGER, C AS _UNSIGNED LONG)
  49.     ' CX = center x coordinate
  50.     ' CY = center y coordinate
  51.     '  a = semimajor axis
  52.     '  b = semiminor axis
  53.     '  C = fill color
  54.     IF a = 0 OR b = 0 THEN EXIT SUB
  55.     DIM h2 AS _INTEGER64
  56.     DIM w2 AS _INTEGER64
  57.     DIM h2w2 AS _INTEGER64
  58.     DIM x AS INTEGER
  59.     DIM y AS INTEGER
  60.     w2 = a * a
  61.     h2 = b * b
  62.     h2w2 = h2 * w2
  63.     LINE (CX - a, CY)-(CX + a, CY), C, BF
  64.     DO WHILE y < b
  65.         y = y + 1
  66.         x = SQR((h2w2 - y * y * w2) \ h2)
  67.         LINE (CX - x, CY + y)-(CX + x, CY + y), C, BF
  68.         LINE (CX - x, CY - y)-(CX + x, CY - y), C, BF
  69.     LOOP
  70.  
  71. SUB EllipseTiltFill (destHandle&, CX, CY, a, b, ang, C AS _UNSIGNED LONG)
  72.     '  destHandle& = destination handle
  73.     '  CX = center x coordinate
  74.     '  CY = center y coordinate
  75.     '   a = semimajor axis
  76.     '   b = semiminor axis
  77.     ' ang = clockwise orientation of semimajor axis in radians (0 default)
  78.     '   C = fill color
  79.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  80.     DIM prc AS _UNSIGNED LONG
  81.     DIM D AS INTEGER, S AS INTEGER
  82.     D = _DEST: S = _SOURCE
  83.     prc = _RGB32(255, 255, 255, 255)
  84.     IF a > b THEN max = a + 1 ELSE max = b + 1
  85.     mx2 = max + max
  86.     tef& = _NEWIMAGE(mx2, mx2)
  87.     _DEST tef&
  88.     _SOURCE tef&
  89.     FOR k = 0 TO 6.283185307179586 + .025 STEP .025
  90.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  91.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  92.         IF k <> 0 THEN
  93.             LINE (lasti, lastj)-(i, j), prc
  94.         ELSE
  95.             PSET (i, j), prc
  96.         END IF
  97.         lasti = i: lastj = j
  98.     NEXT
  99.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  100.     FOR y = 0 TO mx2
  101.         x = 0
  102.         WHILE POINT(x, y) <> prc AND x < mx2
  103.             x = x + 1
  104.         WEND
  105.         xleft(y) = x
  106.         WHILE POINT(x, y) = prc AND x < mx2
  107.             x = x + 1
  108.         WEND
  109.         WHILE POINT(x, y) <> prc AND x < mx2
  110.             x = x + 1
  111.         WEND
  112.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  113.     NEXT
  114.     _DEST destHandle&
  115.     FOR y = 0 TO mx2
  116.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + CX - max, y + CY - max)-(xright(y) + CX - max, y + CY - max), C, BF
  117.     NEXT
  118.     _DEST D: _DEST S
  119.     _FREEIMAGE tef&
  120.  

A couple of things just from quick scan of Bill's 2nd final complete code post (above):

Bill:
Quote
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.

Bill that had problems using the Cartesian coordinate system with y-axis flipped and angles increasing in counter-clockwise direction. Build the Tilted Ellipse code from the TiltedEllipseFill code.

The a and b parameters represent NOT the major and minor axis respectively but the x and y axis respectively ie a is not always greater than or equal to b. And the angle of tilt when 0, would put the a radius parallel with the x-axis.
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: STxAxTIC on February 16, 2019, 09:54:03 am
crap, ran out of time for this, probably for weeks to come

ask Fell or luke for librarian creds
Title: Re: Seeking best ellipse fill function. (For everyone's sake.)
Post by: bplus on February 16, 2019, 10:00:26 am
... dang it, Bill had something else posted that I was replying to, now gone.

OK tested EllipseTilt and Bill did not use the original one without the PAINT because the current one fits TiltedEllipseFill and is changing angle correctly to Basic system coordinates. I still object to descriptions of a and b parameters and offer an alternate wording closer to the actual facts.

Code: QB64: [Select]
  1. _TITLE "Tilted Ellipse Angle test" ' B+ 2019-02-16 check Bill's code for EllipseTilt
  2.  
  3. SCREEN _NEWIMAGE(1000, 700, 32)
  4. _SCREENMOVE 100, 20
  5. CX = 500
  6. CY = 350
  7. a = 100
  8. b = 340
  9.  
  10. FOR ang = 0 TO 2 * _PI STEP _PI(2 / 12) 'draw ellipse at various heights and compare to CIRCLE with aspect i/300
  11.     CLS
  12.     PRINT "Angle tilt:"; INT(_R2D(ang) + .5)
  13.     TiltedEllipseFill 0, CX, CY, a, b, 0, _RGBA(255, 255, 255, 40)
  14.     TiltedEllipseFill 0, CX, CY, a, b, ang, _RGBA(255, 255, 255, 100)
  15.     EllipseTilt CX, CY, a, b, ang, _RGBA(255, 255, 255, 100)
  16.     CIRCLE (CX, CY), a
  17.     CIRCLE (CX, CY), b
  18.     LINE (CX, CY)-(CX + a * COS(ang), CY + a * SIN(ang))
  19.     _DISPLAY
  20.     IF a = _PI(2 / 12) THEN _DELAY 5 ELSE _LIMIT 1
  21.  
  22. SUB TiltedEllipseFill (destHandle&, ox, oy, a, b, ang, col AS _UNSIGNED LONG)
  23.     DIM max AS INTEGER, mx2 AS INTEGER, i AS INTEGER, j AS INTEGER
  24.     DIM prc AS _UNSIGNED LONG
  25.  
  26.     DIM D AS INTEGER, S AS INTEGER 'to preserve old settings
  27.     D = _DEST: S = _SOURCE
  28.  
  29.     prc = _RGB32(255, 255, 255, 255)
  30.     IF a > b THEN max = a + 1 ELSE max = b + 1
  31.     mx2 = max + max
  32.     tef& = _NEWIMAGE(mx2, mx2)
  33.     _DEST tef&
  34.     _SOURCE tef& 'point wont read without this!
  35.     FOR k = 0 TO 6.2832 + .05 STEP .1
  36.         i = max + a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  37.         j = max + a * COS(k) * SIN(ang) - b * SIN(k) * COS(ang)
  38.         IF k <> 0 THEN
  39.             LINE (lasti, lastj)-(i, j), prc
  40.         ELSE
  41.             PSET (i, j), prc
  42.         END IF
  43.         lasti = i: lastj = j
  44.     NEXT
  45.     DIM xleft(mx2) AS INTEGER, xright(mx2) AS INTEGER, x AS INTEGER, y AS INTEGER
  46.     FOR y = 0 TO mx2
  47.         x = 0
  48.         WHILE POINT(x, y) <> prc AND x < mx2
  49.             x = x + 1
  50.         WEND
  51.         xleft(y) = x
  52.         WHILE POINT(x, y) = prc AND x < mx2
  53.             x = x + 1
  54.         WEND
  55.         WHILE POINT(x, y) <> prc AND x < mx2
  56.             x = x + 1
  57.         WEND
  58.         IF x = mx2 THEN xright(y) = xleft(y) ELSE xright(y) = x
  59.     NEXT
  60.     _DEST destHandle&
  61.     FOR y = 0 TO mx2
  62.         IF xleft(y) <> mx2 THEN LINE (xleft(y) + ox - max, y + oy - max)-(xright(y) + ox - max, y + oy - max), col, BF
  63.     NEXT
  64.     _DEST D: _DEST S 'restore those old settings
  65.     _FREEIMAGE tef&
  66.  
  67. SUB EllipseTilt (CX, CY, a, b, ang, C AS _UNSIGNED LONG) 'by STATIC
  68.     '  CX = center x coordinate
  69.     '  CY = center y coordinate
  70.     '   a = Flat ellipse x-axis   '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< B+ changed comment
  71.     '   b = Flat ellipse y-axis   '<<<<<<<<<<<<<<<<<<<<<<<<<<<<<< B+ changed comment
  72.     ' ang = clockwise orientation of semimajor axis in radians (0 default)
  73.     '   C = fill color
  74.     FOR k = 0 TO 6.283185307179586 + .025 STEP .025
  75.         i = a * COS(k) * COS(ang) + b * SIN(k) * SIN(ang)
  76.         j = -a * COS(k) * SIN(ang) + b * SIN(k) * COS(ang)
  77.         i = i + CX
  78.         j = -j + CY
  79.         IF k <> 0 THEN
  80.             LINE -(i, j), C
  81.         ELSE
  82.             PSET (i, j), C
  83.         END IF
  84.     NEXT
  85.  
  86.  
  87.