Author Topic: Circle Packing  (Read 6680 times)

0 Members and 1 Guest are viewing this topic.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Circle Packing
« on: April 07, 2019, 08:50:55 pm »
Another idea from Shiffman, Circle Packing.

Basic random fill:
Code: QB64: [Select]
  1. _TITLE "Circle Packing 1 fill" 'B+ started 2019-04-07  just basic random fill space
  2. CONST xmax = 800
  3. CONST ymax = 600
  4. SCREEN _NEWIMAGE(xmax, ymax, 32)
  5.  
  6. TYPE CircleType
  7.     x AS SINGLE
  8.     y AS SINGLE
  9.     r AS SINGLE
  10.     c AS _UNSIGNED LONG
  11.     growing AS INTEGER
  12. REDIM SHARED circles(1 TO 1) AS CircleType
  13. DIM SHARED flagDone AS INTEGER
  14.  
  15. WHILE _KEYDOWN(27) = 0 AND flagDone = 0
  16.     CLS
  17.     newCircle 1
  18.     drawCircles
  19.     _DISPLAY
  20.     _LIMIT 60
  21. PRINT "done"
  22.  
  23. SUB drawCircles
  24.     FOR i = 1 TO UBOUND(circles)
  25.         IF circles(i).growing THEN 'check new r
  26.             testr = circles(i).r + 2
  27.             IF circles(i).x - testr < 0 OR circles(i).x + testr > xmax OR circles(i).y - testr < 0 OR circles(i).y + testr > ymax THEN
  28.                 circles(i).growing = 0
  29.             ELSE
  30.                 'check if run into another circle
  31.                 FOR j = 1 TO UBOUND(circles)
  32.                     IF j <> i THEN
  33.                         IF SQR((circles(j).x - circles(i).x) ^ 2 + (circles(j).y - circles(i).y) ^ 2) <= testr + circles(j).r THEN
  34.                             circles(i).growing = 0: circles(j).growing = 0
  35.                             EXIT FOR
  36.                         END IF
  37.                     END IF
  38.                 NEXT
  39.             END IF
  40.         END IF
  41.         IF circles(i).growing THEN circles(i).r = testr
  42.         fcirc circles(i).x, circles(i).y, circles(i).r, circles(i).c
  43.     NEXT
  44.     PRINT UBOUND(circles)
  45.  
  46. SUB newCircle (n)
  47.     FOR i = 1 TO n
  48.         attempts = 0
  49.         retry:
  50.         testX = RND * xmax: testY = RND * ymax
  51.         OK = -1
  52.         FOR j = 1 TO UBOUND(circles)
  53.             IF SQR((testX - circles(j).x) ^ 2 + (testY - circles(j).y) ^ 2) < circles(j).r + 2 THEN OK = 0: EXIT FOR
  54.         NEXT
  55.         IF OK THEN
  56.             new = UBOUND(circles) + 1
  57.             REDIM _PRESERVE circles(1 TO new) AS CircleType
  58.             circles(new).x = testX
  59.             circles(new).y = testY
  60.             circles(new).r = 1
  61.             circles(new).growing = -1
  62.             circles(new).c = _RGB32(RND * 155 + 100, RND * 155 + 100, RND * 155 + 100)
  63.         ELSE
  64.             attempts = attempts + 1
  65.             IF attempts > 3000 THEN flagDone = -1: EXIT SUB
  66.             GOTO retry
  67.         END IF
  68.     NEXT
  69.  
  70. 'from Steve Gold standard
  71. SUB fcirc (CX AS INTEGER, CY AS INTEGER, R AS INTEGER, C AS _UNSIGNED LONG)
  72.     DIM Radius AS INTEGER, RadiusError AS INTEGER
  73.     DIM X AS INTEGER, Y AS INTEGER
  74.  
  75.     Radius = ABS(R)
  76.     RadiusError = -Radius
  77.     X = Radius
  78.     Y = 0
  79.  
  80.     IF Radius = 0 THEN PSET (CX, CY), C: EXIT SUB
  81.  
  82.     ' Draw the middle span here so we don't draw it twice in the main loop,
  83.     ' which would be a problem with blending turned on.
  84.     LINE (CX - X, CY)-(CX + X, CY), C, BF
  85.  
  86.     WHILE X > Y
  87.         RadiusError = RadiusError + Y * 2 + 1
  88.         IF RadiusError >= 0 THEN
  89.             IF X <> Y + 1 THEN
  90.                 LINE (CX - Y, CY - X)-(CX + Y, CY - X), C, BF
  91.                 LINE (CX - Y, CY + X)-(CX + Y, CY + X), C, BF
  92.             END IF
  93.             X = X - 1
  94.             RadiusError = RadiusError - X * 2
  95.         END IF
  96.         Y = Y + 1
  97.         LINE (CX - X, CY - Y)-(CX + X, CY - Y), C, BF
  98.         LINE (CX - X, CY + Y)-(CX + X, CY + Y), C, BF
  99.     WEND
  100.  
  101.  
It's more fun with images:
* Circle Packing.zip (Filesize: 182.74 KB, Downloads: 164)
« Last Edit: April 07, 2019, 08:57:23 pm by bplus »

Offline Ashish

  • Forum Resident
  • Posts: 630
  • Never Give Up!
    • View Profile
Re: Circle Packing
« Reply #1 on: April 08, 2019, 03:50:34 am »
Awesome bplus! I like the circle packing of QB64.
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 qb4ever

  • Newbie
  • Posts: 40
  • LOCATE 15,15: COLOR 14: PRINT "Hello World!"
    • View Profile
Re: Circle Packing
« Reply #2 on: April 08, 2019, 07:44:32 am »
Very hypnotic, I am in loop with your program... :o
Well done, great job !

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Circle Packing
« Reply #3 on: April 08, 2019, 10:04:14 am »
Thanks, I am "in loop" with your feedback! :)

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Circle Packing
« Reply #4 on: April 08, 2019, 03:54:04 pm »
Hi Bplus

cool!
Are you sure that you have not made it for WaltDisney cartoon?
I have seen it watching TV!
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Circle Packing
« Reply #5 on: April 08, 2019, 08:09:17 pm »
Of course, we don't have to pack just circles:

Code: QB64: [Select]
  1. _TITLE "Circle Packing 4 nonCircles" 'B+ started 2019-04-08
  2. CONST xmax = 1200
  3. CONST ymax = 600
  4. SCREEN _NEWIMAGE(xmax - 1, ymax - 1, 32)
  5. spbg& = _NEWIMAGE(xmax - 1, ymax - 1, 32)
  6. _DEST spbg&
  7. LINE (0, 0)-(xmax - 1, ymax - 1), _RGB32(0, 0, 0), BF
  8. cText xmax / 2, ymax / 2, 500, _RGB32(255, 255, 255), "QB64"
  9. _SOURCE spbg&
  10. TYPE CircleType
  11.     x AS INTEGER
  12.     y AS INTEGER
  13.     r AS INTEGER
  14.     n AS INTEGER
  15.     a AS SINGLE
  16.     c AS _UNSIGNED LONG
  17.     growing AS INTEGER
  18. REDIM SHARED circles(0) AS CircleType
  19. DIM SHARED flagDone AS INTEGER
  20.  
  21. WHILE _KEYDOWN(27) = 0 AND flagDone = 0
  22.     CLS
  23.     count = count + 1
  24.     newCircle 20
  25.     drawCircles
  26.     _DISPLAY
  27.     _LIMIT 60
  28. PRINT "done"
  29.  
  30. SUB drawCircles
  31.     FOR i = 1 TO UBOUND(circles)
  32.         IF circles(i).growing THEN 'check new r
  33.             testr = circles(i).r + 1
  34.             IF circles(i).x - testr < 0 OR circles(i).x + testr > xmax - 1 OR circles(i).y - testr < 0 OR circles(i).y + testr > ymax - 2 THEN
  35.                 circles(i).growing = 0
  36.             ELSE
  37.                 'check if run into another circle
  38.                 FOR j = 1 TO UBOUND(circles)
  39.                     IF j <> i THEN
  40.                         IF SQR((circles(j).x - circles(i).x) ^ 2 + (circles(j).y - circles(i).y) ^ 2) <= testr + circles(j).r THEN
  41.                             circles(i).growing = 0: circles(j).growing = 0
  42.                             EXIT FOR
  43.                         END IF
  44.                     END IF
  45.                 NEXT
  46.             END IF
  47.         END IF
  48.         IF circles(i).growing THEN circles(i).r = testr
  49.         star circles(i).x, circles(i).y, .3 * circles(i).r, circles(i).r, circles(i).n, circles(i).a, circles(i).c
  50.     NEXT
  51.     PRINT UBOUND(circles)
  52.  
  53. SUB newCircle (n)
  54.     FOR i = 1 TO n
  55.         attempts = 0
  56.         retry:
  57.         testX = INT(RND * xmax): testY = INT(RND * ymax)
  58.         OK = -1
  59.         IF POINT(testX, testY) = _RGB32(255, 255, 255) THEN
  60.             FOR j = 1 TO UBOUND(circles)
  61.                 IF SQR((testX - circles(j).x) ^ 2 + (testY - circles(j).y) ^ 2) < circles(j).r + 3 THEN OK = 0: EXIT FOR
  62.             NEXT
  63.             IF OK THEN
  64.                 new = UBOUND(circles) + 1
  65.                 REDIM _PRESERVE circles(1 TO new) AS CircleType
  66.                 circles(new).x = testX
  67.                 circles(new).y = testY
  68.                 circles(new).r = 3
  69.                 circles(new).a = RND * _PI(2)
  70.                 circles(new).n = 5 + INT(RND * 5)
  71.                 circles(new).growing = -1
  72.                 circles(new).c = _RGB32(RND * 255 + 55, RND * 200 + 55, RND * 200 + 55)
  73.             ELSE
  74.                 attempts = attempts + 1
  75.                 IF attempts > 3000 THEN flagDone = -1: EXIT SUB
  76.                 GOTO retry
  77.             END IF
  78.         ELSE
  79.             GOTO retry
  80.         END IF
  81.     NEXT
  82.  
  83. SUB cText (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  84.     fg = _DEFAULTCOLOR
  85.     'screen snapshot
  86.     cur& = _DEST
  87.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  88.     _DEST I&
  89.     COLOR K, _RGBA32(0, 0, 0, 0)
  90.     _PRINTSTRING (0, 0), txt$
  91.     mult = textHeight / 16
  92.     xlen = LEN(txt$) * 8 * mult
  93.     _PUTIMAGE (x - .5 * xlen, y - .5 * textHeight)-STEP(xlen, textHeight), I&, cur&
  94.     COLOR fg
  95.     _FREEIMAGE I&
  96.  
  97. SUB fIrrPoly (arr(), K AS _UNSIGNED LONG)
  98.     'this just draws a bunch of triangles according to x, y points in arr()
  99.     ox = arr(0): oy = arr(1) 'the first 2 items in arr() need to be center
  100.     FOR i = 2 TO UBOUND(arr) - 3 STEP 2
  101.         ftri ox, oy, arr(i), arr(i + 1), arr(i + 2), arr(i + 3), K
  102.     NEXT
  103.  
  104. SUB star (x, y, rInner, rOuter, nPoints, angleOffset, K AS _UNSIGNED LONG)
  105.     ' x, y are same as for circle,
  106.     ' rInner is center circle radius
  107.     ' rOuter is the outer most point of star
  108.     ' nPoints is the number of points,
  109.     ' angleOffset = angle offset in radians
  110.     ' this is to allow us to spin the star
  111.  
  112.     DIM ar(INT(nPoints) * 4 + 3) 'add two for origin
  113.     pAngle = _PI(2) / nPoints: radAngleOffset = angleOffset - _PI(1 / 2)
  114.     ar(0) = x: ar(1) = y
  115.     ar(2) = x + rOuter * COS(radAngleOffset)
  116.     ar(3) = y + rOuter * SIN(radAngleOffset)
  117.     idx = 4
  118.     FOR i = 0 TO nPoints - 1
  119.         ar(idx) = x + rInner * COS(i * pAngle + radAngleOffset + .5 * pAngle)
  120.         idx = idx + 1
  121.         ar(idx) = y + rInner * SIN(i * pAngle + radAngleOffset + .5 * pAngle)
  122.         idx = idx + 1
  123.         ar(idx) = x + rOuter * COS((i + 1) * pAngle + radAngleOffset)
  124.         idx = idx + 1
  125.         ar(idx) = y + rOuter * SIN((i + 1) * pAngle + radAngleOffset)
  126.         idx = idx + 1
  127.     NEXT
  128.     fIrrPoly ar(), K
  129.  
  130. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  131.     a& = _NEWIMAGE(1, 1, 32)
  132.     _DEST a&
  133.     PSET (0, 0), K
  134.     _DEST 0
  135.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  136.     _FREEIMAGE a& '<<< this is important!
  137.  
  138.  

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Circle Packing
« Reply #6 on: April 09, 2019, 12:17:22 am »
Packing images:
Code: QB64: [Select]
  1. _TITLE "Circle Packing 5 image packing" 'B+ started 2019-04-09
  2. CONST xmax = 1200
  3. CONST ymax = 600
  4. SCREEN _NEWIMAGE(xmax - 1, ymax - 1, 32)
  5. spbg& = _NEWIMAGE(xmax - 1, ymax - 1, 32)
  6. _DEST spbg&
  7. LINE (0, 0)-(xmax - 1, ymax - 1), _RGB32(0, 0, 0), BF
  8. cText xmax / 2, ymax / 2, 500, _RGB32(255, 255, 255), "QB64"
  9. _SOURCE spbg&
  10. TYPE CircleType
  11.     x AS INTEGER
  12.     y AS INTEGER
  13.     r AS INTEGER
  14.     s AS STRING * 1
  15.     c AS _UNSIGNED LONG
  16.     growing AS INTEGER
  17. REDIM SHARED circles(0) AS CircleType
  18. DIM SHARED flagDone AS INTEGER
  19.  
  20. WHILE _KEYDOWN(27) = 0 AND flagDone = 0
  21.     CLS
  22.     count = count + 1
  23.     newCircle 20
  24.     drawCircles
  25.     _DISPLAY
  26.     _LIMIT 60
  27. PRINT "done"
  28.  
  29. SUB drawCircles
  30.     FOR i = 1 TO UBOUND(circles)
  31.         IF circles(i).growing THEN 'check new r
  32.             testr = circles(i).r + 1
  33.             IF circles(i).x - testr < 0 OR circles(i).x + testr > xmax - 1 OR circles(i).y - testr < 0 OR circles(i).y + testr > ymax - 2 THEN
  34.                 circles(i).growing = 0
  35.             ELSE
  36.                 'check if run into another circle
  37.                 FOR j = 1 TO UBOUND(circles)
  38.                     IF j <> i THEN
  39.                         IF SQR((circles(j).x - circles(i).x) ^ 2 + (circles(j).y - circles(i).y) ^ 2) <= testr + circles(j).r THEN
  40.                             circles(i).growing = 0: circles(j).growing = 0
  41.                             EXIT FOR
  42.                         END IF
  43.                     END IF
  44.                 NEXT
  45.             END IF
  46.         END IF
  47.         IF circles(i).growing THEN circles(i).r = testr
  48.         cText circles(i).x, circles(i).y, 2 * circles(i).r, circles(i).c, circles(i).s
  49.     NEXT
  50.     PRINT UBOUND(circles)
  51.  
  52. SUB newCircle (n)
  53.     FOR i = 1 TO n
  54.         attempts = 0
  55.         retry:
  56.         testX = INT(RND * xmax): testY = INT(RND * ymax)
  57.         OK = -1
  58.         IF POINT(testX, testY) = _RGB32(255, 255, 255) THEN
  59.             FOR j = 1 TO UBOUND(circles)
  60.                 IF SQR((testX - circles(j).x) ^ 2 + (testY - circles(j).y) ^ 2) < circles(j).r + 3 THEN OK = 0: EXIT FOR
  61.             NEXT
  62.             IF OK THEN
  63.                 new = UBOUND(circles) + 1
  64.                 REDIM _PRESERVE circles(1 TO new) AS CircleType
  65.                 circles(new).x = testX
  66.                 circles(new).y = testY
  67.                 circles(new).r = 3
  68.                 circles(new).s = CHR$(RND * 96 + 32)
  69.                 circles(new).growing = -1
  70.                 circles(new).c = _RGB32(RND * 255 + 55, RND * 200 + 55, RND * 200 + 55)
  71.             ELSE
  72.                 attempts = attempts + 1
  73.                 IF attempts > 3000 THEN flagDone = -1: EXIT SUB
  74.                 GOTO retry
  75.             END IF
  76.         ELSE
  77.             GOTO retry
  78.         END IF
  79.     NEXT
  80.  
  81. SUB cText (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  82.     fg = _DEFAULTCOLOR
  83.     'screen snapshot
  84.     cur& = _DEST
  85.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  86.     _DEST I&
  87.     COLOR K, _RGBA32(0, 0, 0, 0)
  88.     _PRINTSTRING (0, 0), txt$
  89.     mult = textHeight / 16
  90.     xlen = LEN(txt$) * 8 * mult
  91.     _PUTIMAGE (x - .5 * xlen, y - .5 * textHeight)-STEP(xlen, textHeight), I&, cur&
  92.     COLOR fg
  93.     _FREEIMAGE I&
  94.  
  95.  

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Circle Packing
« Reply #7 on: April 09, 2019, 06:02:13 am »
Thanks Bplus
very cool !
Programming isn't difficult, only it's  consuming time and coffee

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Circle Packing
« Reply #8 on: April 09, 2019, 08:19:59 am »
Thanks TempodiBasic, I am considering packing with cartoon images. ;-))

Offline TempodiBasic

  • Forum Resident
  • Posts: 1792
    • View Profile
Re: Circle Packing
« Reply #9 on: April 09, 2019, 08:43:55 am »
try with my avatar at first :-))
Programming isn't difficult, only it's  consuming time and coffee

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Circle Packing
« Reply #10 on: April 09, 2019, 07:43:55 pm »
impressive B+. I took the liberty of making MINOR modifications that do not affect output EXCEPT to make it a bit faster. Please enjoy this faster but otherwise EXACTLY the same output:
Code: QB64: [Select]
  1. _TITLE "Circle Packing 4 nonCircles" 'B+ started 2019-04-08
  2. CONST xmax = 1200
  3. CONST ymax = 600
  4. SCREEN _NEWIMAGE(xmax - 1, ymax - 1, 32)
  5. '_SCREENMOVE _MIDDLE
  6. spbg& = _NEWIMAGE(xmax - 1, ymax - 1, 32)
  7. _DEST spbg&
  8. LINE (0, 0)-(xmax - 1, ymax - 1), _RGB32(0, 0, 0), BF
  9. cText xmax / 2, ymax / 2, 500, _RGB32(255, 255, 255), "QB64"
  10. _SOURCE spbg&
  11. TYPE CircleType
  12.     x AS INTEGER
  13.     y AS INTEGER
  14.     r AS INTEGER
  15.     n AS INTEGER
  16.     a AS SINGLE
  17.     c AS _UNSIGNED LONG
  18.     growing AS INTEGER
  19. REDIM SHARED circles(0) AS CircleType
  20. DIM SHARED flagDone AS INTEGER
  21.  
  22. WHILE _KEYDOWN(27) = 0 AND flagDone = 0
  23.     CLS
  24.     count = count + 1
  25.     newCircle 20
  26.     drawCircles
  27.     _DISPLAY
  28.     _LIMIT 30 '* originally 60
  29. PRINT "done"
  30.  
  31. SUB drawCircles
  32.     FOR i = 1 TO UBOUND(circles)
  33.         IF circles(i).growing THEN 'check new r
  34.             testr = circles(i).r + 1
  35.             IF circles(i).x - testr < 0 OR circles(i).x + testr > xmax - 1 OR circles(i).y - testr < 0 OR circles(i).y + testr > ymax - 2 THEN
  36.                 circles(i).growing = 0
  37.             ELSE
  38.                 'check if run into another circle
  39.                 FOR j = 1 TO UBOUND(circles)
  40.                     IF j <> i THEN
  41.                         IF ABS(circles(j).x - circles(i).x) <= testr + circles(j).r THEN
  42.                             IF ABS(circles(j).y - circles(i).y) <= testr + circles(j).r THEN
  43.                                 circles(i).growing = 0: circles(j).growing = 0
  44.                                 EXIT FOR
  45.                             END IF
  46.                         END IF
  47.                     END IF
  48.                 NEXT
  49.             END IF
  50.         END IF
  51.         IF circles(i).growing THEN circles(i).r = testr
  52.         star circles(i).x, circles(i).y, .3 * circles(i).r, circles(i).r, circles(i).n, circles(i).a, circles(i).c
  53.     NEXT
  54.     'PRINT UBOUND(circles);
  55.  
  56. SUB newCircle (n)
  57.     FOR i = 1 TO n
  58.         attempts = 0
  59.         retry:
  60.         testX = INT(RND * xmax): testY = INT(RND * ymax)
  61.         OK = -1
  62.         IF POINT(testX, testY) = _RGB32(255, 255, 255) THEN
  63.             FOR j = 1 TO UBOUND(circles)
  64.                 IF ABS(testX - circles(j).x) < circles(j).r + 3 THEN
  65.                     IF ABS(testY - circles(j).y) < circles(j).r + 3 THEN
  66.                         OK = 0: EXIT FOR
  67.                     END IF
  68.                 END IF
  69.             NEXT
  70.             IF OK THEN
  71.                 new = UBOUND(circles) + 1
  72.                 REDIM _PRESERVE circles(1 TO new) AS CircleType
  73.                 circles(new).x = testX
  74.                 circles(new).y = testY
  75.                 circles(new).r = 3
  76.                 circles(new).a = RND * _PI(2)
  77.                 circles(new).n = 5 + INT(RND * 5)
  78.                 circles(new).growing = -1
  79.                 circles(new).c = _RGB32(RND * 255 + 55, RND * 200 + 55, RND * 200 + 55)
  80.             ELSE
  81.                 attempts = attempts + 1
  82.                 IF attempts > 3000 THEN flagDone = -1: EXIT SUB
  83.                 GOTO retry
  84.             END IF
  85.         ELSE
  86.             GOTO retry
  87.         END IF
  88.     NEXT
  89.  
  90. SUB cText (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  91.     fg = _DEFAULTCOLOR
  92.     'screen snapshot
  93.     cur& = _DEST
  94.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  95.     _DEST I&
  96.     COLOR K, _RGBA32(0, 0, 0, 0)
  97.     _PRINTSTRING (0, 0), txt$
  98.     mult = textHeight / 16
  99.     xlen = LEN(txt$) * 8 * mult
  100.     _PUTIMAGE (x - .5 * xlen, y - .5 * textHeight)-STEP(xlen, textHeight), I&, cur&
  101.     COLOR fg
  102.     _FREEIMAGE I&
  103.  
  104. SUB fIrrPoly (arr(), K AS _UNSIGNED LONG)
  105.     'this just draws a bunch of triangles according to x, y points in arr()
  106.     ox = arr(0): oy = arr(1) 'the first 2 items in arr() need to be center
  107.     FOR i = 2 TO UBOUND(arr) - 3 STEP 2
  108.         ftri ox, oy, arr(i), arr(i + 1), arr(i + 2), arr(i + 3), K
  109.     NEXT
  110.  
  111. SUB star (x, y, rInner, rOuter, nPoints, angleOffset, K AS _UNSIGNED LONG)
  112.     ' x, y are same as for circle,
  113.     ' rInner is center circle radius
  114.     ' rOuter is the outer most point of star
  115.     ' nPoints is the number of points,
  116.     ' angleOffset = angle offset in radians
  117.     ' this is to allow us to spin the star
  118.  
  119.     DIM ar(INT(nPoints) * 4 + 3) 'add two for origin
  120.     pAngle = _PI(2) / nPoints: radAngleOffset = angleOffset - _PI(1 / 2)
  121.     ar(0) = x: ar(1) = y
  122.     ar(2) = x + rOuter * COS(radAngleOffset)
  123.     ar(3) = y + rOuter * SIN(radAngleOffset)
  124.     idx = 4
  125.     FOR i = 0 TO nPoints - 1
  126.         ar(idx) = x + rInner * COS(i * pAngle + radAngleOffset + .5 * pAngle)
  127.         idx = idx + 1
  128.         ar(idx) = y + rInner * SIN(i * pAngle + radAngleOffset + .5 * pAngle)
  129.         idx = idx + 1
  130.         ar(idx) = x + rOuter * COS((i + 1) * pAngle + radAngleOffset)
  131.         idx = idx + 1
  132.         ar(idx) = y + rOuter * SIN((i + 1) * pAngle + radAngleOffset)
  133.         idx = idx + 1
  134.     NEXT
  135.     fIrrPoly ar(), K
  136.  
  137. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  138.     a& = _NEWIMAGE(1, 1, 32)
  139.     _DEST a&
  140.     PSET (0, 0), K
  141.     _DEST 0
  142.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  143.     _FREEIMAGE a& '<<< this is important!
  144.  


all that squaring and square root stuff REALLY penalizes the performance. Excellent work. A+ for B+ :). You can change the _LIMIT to 30 and still get a cool effect. It then runs about the same speed as your original code, but the star placement and rendering is MUCH faster without the squaring and square roots. at _LIMIT 30, the placement and rendering are approximately the same as your original code at _LIMIT 60. Very cool program though Corrected as you pointed out.
« Last Edit: April 09, 2019, 09:24:46 pm by codeguy »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Circle Packing
« Reply #11 on: April 09, 2019, 08:39:11 pm »
Code: QB64: [Select]
  1.                         IF ABS(circles(j).x - circles(i).x) <= testr THEN
  2.                             IF ABS(circles(j).y - circles(i).y) <= testr + circles(j).r THEN
  3.                                 circles(i).growing = 0: circles(j).growing = 0
  4.                                 EXIT FOR
  5.                             END IF
  6.                         END IF
  7.  

replaces:
Code: QB64: [Select]
  1.                        IF SQR((circles(j).x - circles(i).x) ^ 2 + (circles(j).y - circles(i).y) ^ 2) <= testr THEN
  2.                             circles(i).growing = 0: circles(j).growing = 0
  3.                             EXIT FOR
  4.                         END IF
  5.  

I see it, I like it! I will use this lesson in the future. Thank you!

oops! I see something missing in first line
IF ABS(circles(j).x - circles(i).x) <= testr THEN

should be
IF ABS(circles(j).x - circles(i).x) <= testr + circles(j).r

Update: on second thought, since the hypotenuse is considerably shorter than sum of two legs (unless 1 leg is really short)...
I am going to try to work up an alternative that even avoids ABS.

« Last Edit: April 09, 2019, 09:05:11 pm by bplus »

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Circle Packing
« Reply #12 on: April 09, 2019, 09:32:05 pm »
No SQR, no ^2, no ABS and remains accurate to hypotenuse distances compared to leg sums.
Code: QB64: [Select]
  1. FUNCTION distLessCheck (x1, x2, y1, y2, checkThis)
  2.     dx = x1 - x2: dy = y1 - y2
  3.     IF dx * dx + dy * dy < checkThis * checkThis THEN distLessCheck = -1 ELSE distLessCheck = 0
  4.  

Code: QB64: [Select]
  1. _TITLE "Circle Packing 4-B nonCircles" 'B+ started 2019-04-09 update with distLessCheck function
  2. CONST xmax = 1200
  3. CONST ymax = 600
  4. SCREEN _NEWIMAGE(xmax - 1, ymax - 1, 32)
  5. spbg& = _NEWIMAGE(xmax - 1, ymax - 1, 32)
  6. _DEST spbg&
  7. LINE (0, 0)-(xmax - 1, ymax - 1), _RGB32(0, 0, 0), BF
  8. cText xmax / 2, ymax / 2, 500, _RGB32(255, 255, 255), "QB64"
  9. _SOURCE spbg&
  10. TYPE CircleType
  11.     x AS INTEGER
  12.     y AS INTEGER
  13.     r AS INTEGER
  14.     n AS INTEGER
  15.     a AS SINGLE
  16.     c AS _UNSIGNED LONG
  17.     growing AS INTEGER
  18. REDIM SHARED circles(0) AS CircleType
  19. DIM SHARED flagDone AS INTEGER
  20.  
  21. WHILE _KEYDOWN(27) = 0 AND flagDone = 0
  22.     CLS
  23.     count = count + 1
  24.     newCircle 20
  25.     drawCircles
  26.     _DISPLAY
  27.     _LIMIT 60
  28. PRINT "done"
  29.  
  30. SUB drawCircles
  31.     FOR i = 1 TO UBOUND(circles)
  32.         IF circles(i).growing THEN 'check new r
  33.             testr = circles(i).r + 1
  34.             IF circles(i).x - testr < 0 OR circles(i).x + testr > xmax - 1 OR circles(i).y - testr < 0 OR circles(i).y + testr > ymax - 2 THEN
  35.                 circles(i).growing = 0
  36.             ELSE
  37.                 'check if run into another circle
  38.                 FOR j = 1 TO UBOUND(circles)
  39.                     IF j <> i THEN
  40.                         IF distLessCheck(circles(j).x, circles(i).x, circles(j).y, circles(i).y, testr + circles(j).r) THEN
  41.                             'IF SQR((circles(j).x - circles(i).x) ^ 2 + (circles(j).y - circles(i).y) ^ 2) <= testr + circles(j).r THEN
  42.                             circles(i).growing = 0: circles(j).growing = 0
  43.                             EXIT FOR
  44.                         END IF
  45.                     END IF
  46.                 NEXT
  47.             END IF
  48.         END IF
  49.         IF circles(i).growing THEN circles(i).r = testr
  50.         star circles(i).x, circles(i).y, .3 * circles(i).r, circles(i).r, circles(i).n, circles(i).a, circles(i).c
  51.     NEXT
  52.     PRINT UBOUND(circles)
  53.  
  54. SUB newCircle (n)
  55.     FOR i = 1 TO n
  56.         attempts = 0
  57.         retry:
  58.         testX = INT(RND * xmax): testY = INT(RND * ymax)
  59.         OK = -1
  60.         IF POINT(testX, testY) = _RGB32(255, 255, 255) THEN
  61.             FOR j = 1 TO UBOUND(circles)
  62.                 IF distLessCheck(testX, circles(j).x, testY, circles(j).y, circles(j).r + 3) THEN OK = 0: EXIT FOR
  63.                 'IF SQR((testX - circles(j).x) ^ 2 + (testY - circles(j).y) ^ 2) < circles(j).r + 3 THEN OK = 0: EXIT FOR
  64.             NEXT
  65.             IF OK THEN
  66.                 new = UBOUND(circles) + 1
  67.                 REDIM _PRESERVE circles(1 TO new) AS CircleType
  68.                 circles(new).x = testX
  69.                 circles(new).y = testY
  70.                 circles(new).r = 3
  71.                 circles(new).a = RND * _PI(2)
  72.                 circles(new).n = 5 + INT(RND * 5)
  73.                 circles(new).growing = -1
  74.                 circles(new).c = _RGB32(RND * 255 + 55, RND * 200 + 55, RND * 200 + 55)
  75.             ELSE
  76.                 attempts = attempts + 1
  77.                 IF attempts > 3000 THEN flagDone = -1: EXIT SUB
  78.                 GOTO retry
  79.             END IF
  80.         ELSE
  81.             GOTO retry
  82.         END IF
  83.     NEXT
  84.  
  85. SUB cText (x, y, textHeight, K AS _UNSIGNED LONG, txt$)
  86.     fg = _DEFAULTCOLOR
  87.     'screen snapshot
  88.     cur& = _DEST
  89.     I& = _NEWIMAGE(8 * LEN(txt$), 16, 32)
  90.     _DEST I&
  91.     COLOR K, _RGBA32(0, 0, 0, 0)
  92.     _PRINTSTRING (0, 0), txt$
  93.     mult = textHeight / 16
  94.     xlen = LEN(txt$) * 8 * mult
  95.     _PUTIMAGE (x - .5 * xlen, y - .5 * textHeight)-STEP(xlen, textHeight), I&, cur&
  96.     COLOR fg
  97.     _FREEIMAGE I&
  98.  
  99. SUB fIrrPoly (arr(), K AS _UNSIGNED LONG)
  100.     'this just draws a bunch of triangles according to x, y points in arr()
  101.     ox = arr(0): oy = arr(1) 'the first 2 items in arr() need to be center
  102.     FOR i = 2 TO UBOUND(arr) - 3 STEP 2
  103.         ftri ox, oy, arr(i), arr(i + 1), arr(i + 2), arr(i + 3), K
  104.     NEXT
  105.  
  106. SUB star (x, y, rInner, rOuter, nPoints, angleOffset, K AS _UNSIGNED LONG)
  107.     ' x, y are same as for circle,
  108.     ' rInner is center circle radius
  109.     ' rOuter is the outer most point of star
  110.     ' nPoints is the number of points,
  111.     ' angleOffset = angle offset in radians
  112.     ' this is to allow us to spin the star
  113.  
  114.     DIM ar(INT(nPoints) * 4 + 3) 'add two for origin
  115.     pAngle = _PI(2) / nPoints: radAngleOffset = angleOffset - _PI(1 / 2)
  116.     ar(0) = x: ar(1) = y
  117.     ar(2) = x + rOuter * COS(radAngleOffset)
  118.     ar(3) = y + rOuter * SIN(radAngleOffset)
  119.     idx = 4
  120.     FOR i = 0 TO nPoints - 1
  121.         ar(idx) = x + rInner * COS(i * pAngle + radAngleOffset + .5 * pAngle)
  122.         idx = idx + 1
  123.         ar(idx) = y + rInner * SIN(i * pAngle + radAngleOffset + .5 * pAngle)
  124.         idx = idx + 1
  125.         ar(idx) = x + rOuter * COS((i + 1) * pAngle + radAngleOffset)
  126.         idx = idx + 1
  127.         ar(idx) = y + rOuter * SIN((i + 1) * pAngle + radAngleOffset)
  128.         idx = idx + 1
  129.     NEXT
  130.     fIrrPoly ar(), K
  131.  
  132. SUB ftri (x1, y1, x2, y2, x3, y3, K AS _UNSIGNED LONG)
  133.     a& = _NEWIMAGE(1, 1, 32)
  134.     _DEST a&
  135.     PSET (0, 0), K
  136.     _DEST 0
  137.     _MAPTRIANGLE _SEAMLESS(0, 0)-(0, 0)-(0, 0), a& TO(x1, y1)-(x2, y2)-(x3, y3)
  138.     _FREEIMAGE a& '<<< this is important!
  139.  
  140. FUNCTION distLessCheck (x1, x2, y1, y2, checkThis)
  141.     dx = x1 - x2: dy = y1 - y2
  142.     IF dx * dx + dy * dy < checkThis * checkThis THEN distLessCheck = -1 ELSE distLessCheck = 0
  143.  
  144.  

Next try with Image fun because THAT needed help with speed.

Update: yes, Mr Spock updates much faster.
« Last Edit: April 09, 2019, 09:58:02 pm by bplus »

Offline codeguy

  • Forum Regular
  • Posts: 174
    • View Profile
Re: Circle Packing
« Reply #13 on: April 09, 2019, 09:58:04 pm »
My method eliminates the need for multiplication altogether. It is the same method used for my NSpace demo, which unfortunately became lost. Ugh. But the change should afford you enough time to place and scale small images.

Offline bplus

  • Global Moderator
  • Forum Resident
  • Posts: 8053
  • b = b + ...
    • View Profile
Re: Circle Packing
« Reply #14 on: April 09, 2019, 11:06:42 pm »
I have coded a test to compare collision detections of the two white circle, one stationary in center of screen the other moved by mouse.

codeguy, I called your method ABScollision, I called the one I created MultCollides and I called the normal distance method distCollides and here is a model test site. Move mouse around and you will see ABS detecting collisions with the white circle all the way out to the yellow circle if you move mouse down a diagonal line.
Code: QB64: [Select]
  1. _TITLE "Collision Test - move mouse down lines to see ABScollides too often (inside yellow circle)" 'B+ 2019-04-09
  2.  
  3. SCREEN _NEWIMAGE(800, 600, 32)
  4. r1 = 10
  5. r2 = 50
  6. x1 = 400
  7. y1 = 300
  8. y2 = 150
  9. WHILE _KEYDOWN(27) = 0
  10.     CLS
  11.     mx = _MOUSEX: my = _MOUSEY
  12.     LINE (600, 100)-(200, 500)
  13.     LINE (200, 100)-(600, 500)
  14.     CIRCLE (x1, y1), r1
  15.     CIRCLE (mx, my), r2
  16.     CIRCLE (x1, y1), 28, _RGB32(255, 255, 0)
  17.     LOCATE 2, 10: PRINT "ABScollides ="; ABScollides(x1, mx, y1, my, r1, r2)
  18.     LOCATE 2, 30: PRINT "MultCollides ="; MultCollides(x1, mx, y1, my, r1, r2)
  19.     LOCATE 2, 50: PRINT "distCollides ="; distCollides(x1, mx, y1, my, r1, r2)
  20.     _DISPLAY
  21.     _LIMIT 60
  22.  
  23. FUNCTION ABScollides (x1, x2, y1, y2, r1, r2)
  24.     IF ABS(x1 - x2) < r1 + r2 THEN
  25.         IF ABS(y1 - y2) < r1 + r2 THEN
  26.             ABScollides = -1
  27.         END IF
  28.     END IF
  29.  
  30. FUNCTION MultCollides (x1, x2, y1, y2, r1, r2)
  31.     dx = x1 - x2: dy = y1 - y2
  32.     IF dx * dx + dy * dy < (r1 + r2) * (r1 + r2) THEN MultCollides = -1
  33.  
  34. FUNCTION distCollides (x1, x2, y1, y2, r1, r2)
  35.     IF SQR((x1 - x2) ^ 2 + (y1 - y2) ^ 2) < r1 + r2 THEN distCollides = -1
  36.  
  37.  
collision test.PNG


This demonstrates that the ABScollides method is inaccurate. The yellow circle shows the error found running down the lines with the mouse.
« Last Edit: April 09, 2019, 11:53:18 pm by bplus »