Author Topic: Seeking best ellipse fill function. (For everyone's sake.)  (Read 22643 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #135 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.

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • Steve’s QB64 Archive Forum
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #136 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.  ;)
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #137 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.  
« Last Edit: February 14, 2019, 11:11:37 pm by bplus »

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #138 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?
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #139 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.  

 
CIRCLE Overlap.PNG
 

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.  

 
Gold standard no unexpected overlap.PNG

« Last Edit: February 15, 2019, 10:30:36 am by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #140 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.

Offline _vince

  • Seasoned Forum Regular
  • Posts: 422
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #141 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

want to know why?

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #142 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.
« Last Edit: February 15, 2019, 11:35:58 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #143 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

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

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #144 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.

FellippeHeitor

  • Guest
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #145 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?
« Last Edit: February 15, 2019, 01:04:18 pm by FellippeHeitor »

FellippeHeitor

  • Guest
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #146 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.

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #147 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.  
« Last Edit: February 16, 2019, 01:50:27 am by STxAxTIC »
You're not done when it works, you're done when it's right.

Offline Pete

  • Forum Resident
  • Posts: 2361
  • Cuz I sez so, varmint!
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #148 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
Want to learn how to write code on cave walls? https://www.tapatalk.com/groups/qbasic/qbasic-f1/

Offline STxAxTIC

  • Library Staff
  • Forum Resident
  • Posts: 1091
  • he lives
Re: Seeking best ellipse fill function. (For everyone's sake.)
« Reply #149 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
You're not done when it works, you're done when it's right.