Author Topic: Is this fast enough as general circle fill?  (Read 20093 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #15 on: June 25, 2018, 09:30:55 am »
Slower than Steve's but this fills a regular polygon that approaches a circle as increase the number of sides. It fills the circle with an image and the image is based according to location of mouse (or where ever you want a circular part of image).

This is a circle fill method based on _MAPTRIANGLE, I think it is fast enough to impress!

Code: QB64: [Select]
  1. 'Poly Image Demo 2
  2. 'by bplus started 2018-06-22
  3.  
  4. CONST xmax = 800
  5. CONST ymax = 600
  6. SCREEN _NEWIMAGE(xmax, ymax, 32)
  7. _SCREENMOVE 100, 20
  8.  
  9. stars& = _LOADIMAGE("stars.png")
  10. stuff& = _NEWIMAGE(xmax, ymax, 32)
  11. _DEST stuff&
  12. FOR i = 1 TO 100
  13.     CIRCLE (RND * xmax, RND * ymax), RND * 100, _RGB32(RND * 255, RND * 255, RND * 255)
  14.     CLS
  15.     _SOURCE stuff&
  16.     _PUTIMAGE
  17.     polygonImage stars&, _MOUSEX, _MOUSEY, 250, 50
  18.     _DISPLAY
  19.     _LIMIT 30
  20.  
  21.  
  22. SUB polygonImage (ImageHandle&, xOrigin, yOrigin, radius, nVertex)
  23.     polyAngle = _PI(2) / nVertex
  24.     x1 = xOrigin + radius * COS(polyAngle)
  25.     y1 = yOrigin + radius * SIN(polyAngle)
  26.     FOR i = 2 TO nVertex + 1
  27.         x2 = xOrigin + radius * COS(i * polyAngle)
  28.         y2 = yOrigin + radius * SIN(i * polyAngle)
  29.         _MAPTRIANGLE (xOrigin, yOrigin)-(x1, y1)-(x2, y2), ImageHandle& TO(xOrigin, yOrigin)-(x1, y1)-(x2, y2), 0
  30.         x1 = x2: y1 = y2
  31.     NEXT
  32.  

Attached is code with Stars.png for testing with image file.
« Last Edit: June 25, 2018, 09:35:26 am by bplus »

Offline SMcNeill

  • QB64 Developer
  • Forum Resident
  • Posts: 3972
    • View Profile
    • Steve’s QB64 Archive Forum
Re: Is this fast enough as general circle fill?
« Reply #16 on: June 25, 2018, 09:43:40 am »
For the absolute FASTEST filled circle routine, what one could do is simply pre-calculate the start and end points for each line of a circle of X size, and then save that data into an array.  Then, instead of the program having to do any math, it'd just lookup the plot points directly from memory, and insta-draw the circle.

Take all the math out ahead of time, utilize a lookup table, and it'd be much quicker than anything anybody has shared previously.  Only drawback would be the memory required to store the lookup table, which, in regards to modern OS memory limits, really shouldn't be that big an issue at all, honestly. 
https://github.com/SteveMcNeill/Steve64 — A github collection of all things Steve!

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #17 on: June 25, 2018, 09:47:54 am »
Here is my test code comparing the 2 Methods with just one color. Over 2 times slower but not 10 or 1000 times...

Code: QB64: [Select]
  1. _TITLE "Circle fill: Steve's method versus MapTriangle by bplus started 2018-06-22"
  2. 'QB64 version 2017 1106/82 (the day before they switched to version 1.2)
  3.  
  4. 'steve's method wins easily
  5.  
  6. CONST xmax = 800
  7. CONST ymax = 600
  8. SCREEN _NEWIMAGE(xmax, ymax, 32)
  9. _SCREENMOVE 360, 60
  10. start## = TIMER
  11. 'this is 10 X 10 X 10 runs on circle with different colors
  12. FOR r = 246 TO 255
  13.     FOR g = 246 TO 255
  14.         FOR b = 1 TO 10
  15.             'fpcir xmax / 2, ymax / 2, 300, _RGB32(r, g, b)
  16.             fcirc xmax / 2, ymax / 2, 300, _RGB32(r, g, b)
  17.         NEXT
  18.     NEXT
  19. COLOR _RGB32(255, 255, 255)
  20. PRINT TIMER - start##
  21.  
  22. SUB fpcir (xOrigin AS LONG, yOrigin AS LONG, radius AS LONG, K AS _UNSIGNED LONG)
  23.     a& = _NEWIMAGE(1, 1, 32)
  24.     _DEST a&
  25.     PSET (0, 0), K
  26.     _DEST 0
  27.     DIM x1 AS LONG, y1 AS LONG, x2 AS LONG, y2 AS LONG, i AS INTEGER
  28.     DIM polyAngle AS SINGLE
  29.     polyAngle = _PI(2) / 60
  30.     x1 = xOrigin + radius * COS(polyAngle)
  31.     y1 = yOrigin + radius * SIN(polyAngle)
  32.     FOR i = 2 TO 61
  33.         x2 = xOrigin + radius * COS(i * polyAngle)
  34.         y2 = yOrigin + radius * SIN(i * polyAngle)
  35.         _MAPTRIANGLE (0, 0)-(0, 0)-(0, 0), a& TO(xOrigin, yOrigin)-(x1, y1)-(x2, y2), 0
  36.         x1 = x2: y1 = y2
  37.     NEXT
  38.     _FREEIMAGE a& '<<< this is important!
  39.  
  40. SUB fcirc (CX AS LONG, CY AS LONG, R AS LONG, K AS _UNSIGNED LONG)
  41.     DIM subRadius AS LONG, RadiusError AS LONG
  42.     DIM X AS LONG, Y AS LONG
  43.  
  44.     subRadius = ABS(R)
  45.     RadiusError = -subRadius
  46.     X = subRadius
  47.     Y = 0
  48.  
  49.     IF subRadius = 0 THEN PSET (CX, CY): EXIT SUB
  50.  
  51.     ' Draw the middle span here so we don't draw it twice in the main loop,
  52.     ' which would be a problem with blending turned on.
  53.     LINE (CX - X, CY)-(CX + X, CY), K, BF
  54.  
  55.     WHILE X > Y
  56.         RadiusError = RadiusError + Y * 2 + 1
  57.         IF RadiusError >= 0 THEN
  58.             IF X <> Y + 1 THEN
  59.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), K, BF
  60.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), K, BF
  61.             END IF
  62.             X = X - 1
  63.             RadiusError = RadiusError - X * 2
  64.         END IF
  65.         Y = Y + 1
  66.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), K, BF
  67.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), K, BF
  68.     WEND
  69.  
  70.  

Might use codeguy's "mini step" to adjust number of triangles to take according to size of (near) circle. Here I just tested a large "circle" polygon with 60 sides for speed.

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #18 on: June 25, 2018, 10:23:13 am »
Hi Codeguy. I was watching your program, there are two brakes. The first big brake is Minstep !, it's really low for large diameters and that's why it's so slow. Another - but smaller brake is the call of the sinus and cosine functions during rendering. It is far more advantageous to save these values in a field and then to use them directly for drawing. I made some attempts, the LINE command with the parameter, BF is 50 percent faster than without it, and 40 percent slower with the B parameter than without it. Your turn-around solution with only a quarter rotation is very nice, it saves a lot of extra time.

Code: QB64: [Select]
  1.  
  2. '0.105 original
  3. REDIM Px(0) AS SINGLE, Py(0) AS SINGLE
  4. Demo& = _NEWIMAGE(1366, 768, 256)
  5. SCREEN Demo&
  6. St! = TIMER(.001)
  7. Radius = 1000
  8. Cx = Radius
  9. Cy = Radius
  10.  
  11. ' Minstep: When someone rewrite it to function, I would leave this as an optional parameter, letting everyone decide by themselves how much smooth circle wants ...
  12. 'Minstep! = 1 / (2 * _PI * Radius) 'why so? For circle R = 250: 1 / (6.28 * 250) = 0.0006. This is very small step...
  13. Minstep! = 1 / _PI / (Radius / 10) ' for Circle R = 250: 1 / 3.14 / 25 = 0.01, it is enought...or not?
  14.  
  15. FOR s = 0 TO _PI / 2 STEP Minstep!
  16.     Px(i) = Radius * COS(s!)
  17.     Py(i) = Radius * SIN(s!)
  18.     i = i + 1
  19.     REDIM _PRESERVE Px(i) AS SINGLE
  20.     REDIM _PRESERVE Py(i) AS SINGLE
  21.  
  22.  
  23. FOR s = 0 TO UBOUND(Px)
  24.     LINE (Cx - Px(s), Cy - Py(s))-(Cx + Px(s), Cy + Py(s)), 127, BF
  25.  
  26. F! = TIMER(.001)
  27. LOCATE 1, 1
  28. PRINT F! - St!;
  29.  
  30.  

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #19 on: June 25, 2018, 10:41:16 am »
For some reason, I can not edit the previous post, so here is the Minstep! fixed so that it also works on small radius.

Code: QB64: [Select]
  1.  
  2.  
  3.  
  4. '0.105 original
  5. REDIM Px(0) AS SINGLE, Py(0) AS SINGLE, s AS SINGLE, st AS SINGLE, radius AS INTEGER, Cx AS INTEGER, Cy AS INTEGER
  6. Demo& = _NEWIMAGE(1366, 768, 256)
  7. SCREEN Demo&
  8. st! = TIMER(.001)
  9. radius = 555
  10. Cx = 250 'radius
  11. Cy = 400 'radius
  12.  
  13. ' Minstep: When someone rewrite it to function, I would leave this as an optional parameter, letting everyone decide by themselves how much smooth circle wants ...
  14. 'Minstep! = 1 / (2 * _PI * Radius) 'why so? For circle R = 250: 1 / (6.28 * 250) = 0.0006. This is very small step...
  15. Minstep! = 1 / (_PI / 2 * radius)
  16.  
  17. FOR s = 0 TO _PI / 2 STEP Minstep!
  18.     Px(i) = radius * COS(s!)
  19.     Py(i) = radius * SIN(s!)
  20.     i = i + 1
  21.     REDIM _PRESERVE Px(i) AS SINGLE
  22.     REDIM _PRESERVE Py(i) AS SINGLE
  23.  
  24.  
  25. FOR s = 0 TO UBOUND(Px)
  26.     LINE (Cx - Px(s), Cy - Py(s))-(Cx + Px(s), Cy + Py(s)), 127, BF
  27.  
  28. F! = TIMER(.001)
  29. LOCATE 1, 1
  30. PRINT F! - st!;
  31.  
  32.  
« Last Edit: June 25, 2018, 10:42:21 am by Petr »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #20 on: June 25, 2018, 10:55:32 am »
Slower than Steve's but this fills a regular polygon that approaches a circle as increase the number of sides. It fills the circle with an image and the image is based according to location of mouse (or where ever you want a circular part of image).

This is a circle fill method based on _MAPTRIANGLE, I think it is fast enough to impress!

Code: QB64: [Select]
  1. 'Poly Image Demo 2
  2. 'by bplus started 2018-06-22
  3.  
  4. CONST xmax = 800
  5. CONST ymax = 600
  6. SCREEN _NEWIMAGE(xmax, ymax, 32)
  7. _SCREENMOVE 100, 20
  8.  
  9. stars& = _LOADIMAGE("stars.png")
  10. stuff& = _NEWIMAGE(xmax, ymax, 32)
  11. _DEST stuff&
  12. FOR i = 1 TO 100
  13.     CIRCLE (RND * xmax, RND * ymax), RND * 100, _RGB32(RND * 255, RND * 255, RND * 255)
  14.     CLS
  15.     _SOURCE stuff&
  16.     _PUTIMAGE
  17.     polygonImage stars&, _MOUSEX, _MOUSEY, 250, 50
  18.     _DISPLAY
  19.     _LIMIT 30
  20.  
  21.  
  22. SUB polygonImage (ImageHandle&, xOrigin, yOrigin, radius, nVertex)
  23.     polyAngle = _PI(2) / nVertex
  24.     x1 = xOrigin + radius * COS(polyAngle)
  25.     y1 = yOrigin + radius * SIN(polyAngle)
  26.     FOR i = 2 TO nVertex + 1
  27.         x2 = xOrigin + radius * COS(i * polyAngle)
  28.         y2 = yOrigin + radius * SIN(i * polyAngle)
  29.         _MAPTRIANGLE (xOrigin, yOrigin)-(x1, y1)-(x2, y2), ImageHandle& TO(xOrigin, yOrigin)-(x1, y1)-(x2, y2), 0
  30.         x1 = x2: y1 = y2
  31.     NEXT
  32.  

Attached is code with Stars.png for testing with image file.


Hi Bplus, You can use hardware images for really fast output:

Code: QB64: [Select]
  1. 'Poly Image Demo 2
  2. 'by bplus started 2018-06-22
  3.  
  4. CONST xmax = 800
  5. CONST ymax = 600
  6. SCREEN _NEWIMAGE(xmax, ymax, 32)
  7. _SCREENMOVE 100, 20
  8.  
  9. star& = _LOADIMAGE("stars.png")
  10. stars& = _COPYIMAGE(star&, 33)
  11. stuff& = _NEWIMAGE(xmax, ymax, 32)
  12. _DEST stuff&
  13. FOR i = 1 TO 100
  14.     CIRCLE (RND * xmax, RND * ymax), RND * 100, _RGB32(RND * 255, RND * 255, RND * 255)
  15.     '    CLS not need for hardware images and in this case also not, _PUTIMAGE in this case rewrite screen.
  16.     _SOURCE stuff&
  17.     _PUTIMAGE
  18.     polygonImage stars&, _MOUSEX, _MOUSEY, 250, 50
  19.     _DISPLAY
  20.     _LIMIT 30
  21.  
  22.  
  23. SUB polygonImage (ImageHandle&, xOrigin, yOrigin, radius, nVertex) 'Where I just saw it.... :-D
  24.     polyAngle = _PI(2) / nVertex
  25.     x1 = xOrigin + radius * COS(polyAngle)
  26.     y1 = yOrigin + radius * SIN(polyAngle)
  27.     FOR i = 2 TO nVertex + 1
  28.         x2 = xOrigin + radius * COS(i * polyAngle)
  29.         y2 = yOrigin + radius * SIN(i * polyAngle)
  30.         _MAPTRIANGLE (xOrigin, yOrigin)-(x1, y1)-(x2, y2), ImageHandle& TO(xOrigin, yOrigin)-(x1, y1)-(x2, y2), 0
  31.         x1 = x2: y1 = y2
  32.     NEXT
  33.  
  34.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #21 on: June 25, 2018, 11:16:13 am »
Code: QB64: [Select]
  1. stars& = _COPYIMAGE(star&, 33)

Petr, Using this line is causing a line of distortion on y axis right down the 270 to 90 degree line from center??? for my system when I move the mouse around. Using the image as I had directly was better (for my system anyway).

Does anyone else see it? It's seems about 2-4 (maybe more) pixels wide.



PS Petr: Right! CLS was not needed, leftover from before drawing "stuff".
« Last Edit: June 25, 2018, 11:19:34 am by bplus »

Offline Petr

  • Forum Resident
  • Posts: 1720
  • The best code is the DNA of the hops.
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #22 on: June 25, 2018, 12:44:00 pm »
Quote
Petr, Using this line is causing a line of distortion on y axis right down the 270 to 90 degree line from center??? for my system when I move the mouse around. Using the image as I had directly was better (for my system anyway).

Does anyone else see it? It's seems about 2-4 (maybe more) pixels wide.

Yes, right under the mouse. It is interesting. It is best see in bright places. And it does with a hardware image only. So I have it not seen this yet.

Offline SkyCharger001

  • Newbie
  • Posts: 14
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #23 on: June 25, 2018, 02:55:44 pm »
about the LINE BF,
Code: QB64: [Select]
  1. LINE(cx%-px!,cy%-py!)-(cx%+px!,cy%+py!),63,bf
instead of
Code: QB64: [Select]
  1. LINE(cx%-px!,cy%-py!)-(cx%+px!,cy%-py!),63,bf
should save you half of the LINE calls

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #24 on: June 25, 2018, 04:28:03 pm »
about the LINE BF,
Code: QB64: [Select]
  1. LINE(cx%-px!,cy%-py!)-(cx%+px!,cy%+py!),63,bf
instead of
Code: QB64: [Select]
  1. LINE(cx%-px!,cy%-py!)-(cx%+px!,cy%-py!),63,bf
should save you half of the LINE calls

Yes, but if you are using alpha coloring, the overlapping boxes might NOT give you an even shade.

Offline _vince

  • Seasoned Forum Regular
  • Posts: 422
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #25 on: June 25, 2018, 06:45:58 pm »
These claims I strongly refuse to believe that anything's faster than that by Steve.

Offline SkyCharger001

  • Newbie
  • Posts: 14
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #26 on: June 26, 2018, 04:44:11 am »
about the LINE BF,
Code: QB64: [Select]
  1. LINE(cx%-px!,cy%-py!)-(cx%+px!,cy%+py!),63,bf
instead of
Code: QB64: [Select]
  1. LINE(cx%-px!,cy%-py!)-(cx%+px!,cy%-py!),63,bf
should save you half of the LINE calls

Yes, but if you are using alpha coloring, the overlapping boxes might NOT give you an even shade.
Ah, didn't think about that.
one solution (that might ruin the speed-gain) would be to draw the filled circle on a temporary indexed image with color 0 set to RGBA(0,0,0,0) for masking and color 1 set to whatever RGBA color you want, and _PUTIMAGEing it onto the target image.

Offline zigzag

  • Newbie
  • Posts: 5
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #27 on: June 26, 2018, 07:01:16 am »
Hasn't anyone considered using this method?

Code: QB64: [Select]
  1. Radius% = 1000
  2. Cx% = Radius%
  3. Cy% = Radius%
  4.  
  5. FOR X% = 0 TO Radius%
  6.   Y% = SQR(Radius% * Radius% - X% * X%)
  7.   LINE (Cx% + X%, Cy% - Y%)-(Cx% + X%, Cy% + Y%)
  8.   LINE (Cx% - X%, Cy% - Y%)-(Cx% - X%, Cy% + Y%)

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #28 on: June 26, 2018, 09:06:53 am »
+Zigzag
I guess you are using circle equation (x^2+y^2=r^2) inside the loop and it works. Good to see this code as I've only use these equation on paper graphs.
if (Me.success) {Me.improve()} else {Me.tryAgain()}


My Projects - https://github.com/AshishKingdom?tab=repositories
OpenGL tutorials - https://ashishkingdom.github.io/OpenGL-Tutorials

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Is this fast enough as general circle fill?
« Reply #29 on: June 26, 2018, 09:09:36 am »
Hi zigzag,

Yes! First thing I ever tried. Apparently the SQR function takes allot of time!

Also, it has been recently discussed, counter to our intuition that a line is faster with BF than without.



I think Steve's "Gold Standard" method comes from here:
https://en.wikipedia.org/wiki/Midpoint_circle_algorithm