Author Topic: Bézier Curves (Demo)  (Read 3265 times)

0 Members and 1 Guest are viewing this topic.

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Bézier Curves (Demo)
« on: July 03, 2021, 07:59:39 pm »
Playing with Bézier curves in 2D and 3D space, see also: https://en.wikipedia.org/wiki/B%C3%A9zier_curve

SUB CalcFracPoints is calculating all intersection points for a specific fraction down from the given start degree to the final curve point, hence the very last point (UBOUND) in the output array contains the regular curve point, while the other points building the intersection lines from the start degree down to the first degree. Each degree ends with a stop flag.

Code: QB64: [Select]
  1. _TITLE "Bezier Curve 2D"
  2.  
  3. SCREEN _NEWIMAGE(640, 480, 256)
  4. ti& = _NEWIMAGE(640, 480, 256)
  5.  
  6.     x AS DOUBLE
  7.     y AS DOUBLE
  8.     z AS DOUBLE
  9.     s AS INTEGER
  10. REDIM points(0 TO 4) AS point
  11. REDIM spans(0 TO 2) AS point
  12.  
  13. points(0).x = 150 'start point
  14. points(0).y = 50
  15.  
  16. points(1).x = 50 'control point (handle)
  17. points(1).y = 430
  18.  
  19. points(2).x = 590 'control point (handle)
  20. points(2).y = 350
  21.  
  22. points(3).x = 320 'control point (handle)
  23. points(3).y = 160
  24.  
  25. points(4).x = 590 'end point
  26. points(4).y = 50
  27.  
  28. again:
  29. FOR f# = 0 TO 1.0 STEP 0.0025
  30.     _LIMIT 30
  31.     CalcFracPoints points(), spans(), f#
  32.     _DEST ti&
  33.     x# = spans(UBOUND(spans)).x
  34.     y# = spans(UBOUND(spans)).y
  35.     CIRCLE (x#, y#), 1, 12
  36.     CIRCLE (x#, y#), 2, 12
  37.     CIRCLE (x#, y#), 3, 12
  38.     _DEST 0
  39.     CLS
  40.     _PUTIMAGE , ti&
  41.     LOCATE 1, 1
  42.     PRINT "Fraction ="; f#
  43.     DrawLines points(), &HFFFF
  44.     DrawLines spans(), &B1001100110011001
  45.     FOR i% = LBOUND(spans) TO UBOUND(spans) - 1
  46.         CIRCLE (spans(i%).x, spans(i%).y), 1, 14
  47.         CIRCLE (spans(i%).x, spans(i%).y), 2, 14
  48.     NEXT i%
  49.     CIRCLE (x#, y#), 1, 4
  50.     CIRCLE (x#, y#), 2, 4
  51.     CIRCLE (x#, y#), 3, 12
  52.     CIRCLE (x#, y#), 4, 15
  53.     CIRCLE (x#, y#), 5, 15
  54.     _DISPLAY
  55. NEXT f#
  56. GOTO again
  57.  
  58. SUB CalcFracPoints (pIn() AS point, pOut() AS point, frac#)
  59. iLns% = UBOUND(pIn) - LBOUND(pIn) 'no +1 here, as lines = 1 less than points
  60. oPts% = (iLns% * (iLns% + 1)) / 2 'sum 1 to n, which is n(n+1)/2
  61. REDIM pOut(0 TO oPts% - 1) AS point
  62.  
  63. p% = 0
  64. FOR i% = LBOUND(pIn) TO UBOUND(pIn) - 1
  65.     pOut(p%).x = pIn(i%).x + frac# * (pIn(i% + 1).x - pIn(i%).x)
  66.     pOut(p%).y = pIn(i%).y + frac# * (pIn(i% + 1).y - pIn(i%).y)
  67.     pOut(p%).z = pIn(i%).z + frac# * (pIn(i% + 1).z - pIn(i%).z)
  68.     p% = p% + 1
  69. NEXT i%
  70. pOut(p% - 1).s = -1 'stop flag for drawing
  71.  
  72. FOR j% = iLns% TO 2 STEP -1
  73.     FOR i% = p% - j% TO p% - 2
  74.         pOut(p%).x = pOut(i%).x + frac# * (pOut(i% + 1).x - pOut(i%).x)
  75.         pOut(p%).y = pOut(i%).y + frac# * (pOut(i% + 1).y - pOut(i%).y)
  76.         pOut(p%).z = pOut(i%).z + frac# * (pOut(i% + 1).z - pOut(i%).z)
  77.         p% = p% + 1
  78.     NEXT i%
  79.     pOut(p% - 1).s = -1 'stop flag for drawing
  80. NEXT j%
  81.  
  82. SUB DrawLines (pIn() AS point, sty%)
  83. col~& = 1
  84. FOR i% = LBOUND(pIn) TO UBOUND(pIn) - 1
  85.     LINE (pIn(i%).x, pIn(i%).y)-(pIn(i% + 1).x, pIn(i% + 1).y), col~&, , sty%
  86.     IF pIn(i% + 1).s THEN
  87.         col~& = (col~& + 1) AND 15
  88.         i% = i% + 1 'skip to next sequence
  89.     END IF
  90. NEXT i%
  91.  
  92.  

Code: QB64: [Select]
  1. _TITLE "Bezier Curve 3D"
  2.  
  3. SCREEN _NEWIMAGE(640, 480, 256)
  4. ti& = _NEWIMAGE(640, 480, 256)
  5.  
  6.     x AS DOUBLE
  7.     y AS DOUBLE
  8.     z AS DOUBLE
  9.     s AS INTEGER
  10. REDIM points(0 TO 4) AS point
  11. REDIM spans(0 TO 2) AS point
  12.  
  13. DIM SHARED cx%, cy%
  14. cx% = -100: cy% = 400 '3D space origin
  15.  
  16. points(0).x = 150 'start point
  17. points(0).y = 50
  18. points(0).z = 0
  19.  
  20. points(1).x = 50 'control point (handle)
  21. points(1).y = 430
  22. points(1).z = 300
  23.  
  24. points(2).x = 590 'control point (handle)
  25. points(2).y = 350
  26. points(2).z = -500
  27.  
  28. points(3).x = 320 'control point (handle)
  29. points(3).y = 160
  30. points(3).z = 300
  31.  
  32. points(4).x = 590 'end point
  33. points(4).y = 50
  34. points(4).z = 0
  35.  
  36. again:
  37. _DEST ti&
  38. FOR i% = 0 TO 700 STEP 50
  39.     Line3D i%, 0, 0, i%, 700, 0, 15
  40.     Line3D 0, i%, 0, 700, i%, 0, 15
  41. NEXT i%
  42.  
  43. FOR f# = 0 TO 1.0 STEP 0.0025
  44.     _LIMIT 30
  45.     CalcFracPoints points(), spans(), f#
  46.     _DEST ti&
  47.     x# = spans(UBOUND(spans)).x
  48.     y# = spans(UBOUND(spans)).y
  49.     z# = spans(UBOUND(spans)).z
  50.     Circle3D x#, y#, z#, 1, 0, 12
  51.     _DEST 0
  52.     CLS
  53.     _PUTIMAGE , ti&
  54.     LOCATE 1, 1
  55.     PRINT "Fraction ="; f#
  56.     DrawLines points()
  57.     DrawLines spans()
  58.     FOR i% = LBOUND(spans) TO UBOUND(spans) - 1
  59.         Circle3D spans(i%).x, spans(i%).y, spans(i%).z, 1, 0, 14
  60.     NEXT i%
  61.     Circle3D x#, y#, z#, 2, 0, 4
  62.     _DISPLAY
  63. NEXT f#
  64. GOTO again
  65.  
  66. SUB CalcFracPoints (pIn() AS point, pOut() AS point, frac#)
  67. iLns% = UBOUND(pIn) - LBOUND(pIn) 'no +1 here, as lines = 1 less than points
  68. oPts% = (iLns% * (iLns% + 1)) / 2 'sum 1 to n, which is n(n+1)/2
  69. REDIM pOut(0 TO oPts% - 1) AS point
  70.  
  71. p% = 0
  72. FOR i% = LBOUND(pIn) TO UBOUND(pIn) - 1
  73.     pOut(p%).x = pIn(i%).x + frac# * (pIn(i% + 1).x - pIn(i%).x)
  74.     pOut(p%).y = pIn(i%).y + frac# * (pIn(i% + 1).y - pIn(i%).y)
  75.     pOut(p%).z = pIn(i%).z + frac# * (pIn(i% + 1).z - pIn(i%).z)
  76.     p% = p% + 1
  77. NEXT i%
  78. pOut(p% - 1).s = -1 'stop flag for drawing
  79.  
  80. FOR j% = iLns% TO 2 STEP -1
  81.     FOR i% = p% - j% TO p% - 2
  82.         pOut(p%).x = pOut(i%).x + frac# * (pOut(i% + 1).x - pOut(i%).x)
  83.         pOut(p%).y = pOut(i%).y + frac# * (pOut(i% + 1).y - pOut(i%).y)
  84.         pOut(p%).z = pOut(i%).z + frac# * (pOut(i% + 1).z - pOut(i%).z)
  85.         p% = p% + 1
  86.     NEXT i%
  87.     pOut(p% - 1).s = -1 'stop flag for drawing
  88. NEXT j%
  89.  
  90. SUB DrawLines (pIn() AS point)
  91. col~& = 1
  92. FOR i% = LBOUND(pIn) TO UBOUND(pIn) - 1
  93.     Line3D pIn(i%).x, pIn(i%).y, pIn(i%).z, pIn(i% + 1).x, pIn(i% + 1).y, pIn(i% + 1).z, col~&
  94.     IF pIn(i% + 1).s THEN
  95.         col~& = (col~& + 1) AND 15
  96.         i% = i% + 1 'skip to next sequence
  97.     END IF
  98. NEXT i%
  99.  
  100. SUB Line3D (x1%, y1%, z1%, x2%, y2%, z2%, col%)
  101. 'x1%/y1%/z1% = start, x2%/y2%/z2% = end, col% = color pen
  102. x1# = (x1% + (y1% * 0.1)): z1# = (z1% + (y1% * 0.1))
  103. x2# = (x2% + (y2% * 0.1)): z2# = (z2% + (y2% * 0.1))
  104. LINE (x1# + cx% - 1, -z1# + cy%)-(x2# + cx% - 1, -z2# + cy%), col%
  105. LINE (x1# + cx%, -z1# + cy%)-(x2# + cx%, -z2# + cy%), col%
  106. LINE (x1# + cx% + 1, -z1# + cy%)-(x2# + cx% + 1, -z2# + cy%), col%
  107.  
  108. SUB Circle3D (x%, y%, z%, r%, ba%, col%)
  109. 'x%/y%/z% = center, r% = radius, ba% = B-Axis angle, col% = color pen
  110. mx# = (x% + (y% * 0.1)): mz# = (z% + (y% * 0.1))
  111. zx# = r% * COS(ba% * 0.017453292519943)
  112. zz# = r% * SIN(ba% * 0.017453292519943)
  113. FOR cir% = 0 TO 359 STEP 5
  114.     x# = zx# * COS(cir% * 0.017453292519943)
  115.     y# = r% * SIN(cir% * 0.017453292519943)
  116.     z# = zz# * COS(cir% * 0.017453292519943)
  117.     x# = (x# + (y# * 0.1)): z# = (z# + (y# * 0.1))
  118.     LINE (x# + mx# + cx% - 1, -z# + -mz# + cy% - 1)-(x# + mx# + cx% + 1, -z# + -mz# + cy% + 1), col%, BF
  119. NEXT cir%
  120.  
  121.  
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline _vince

  • Seasoned Forum Regular
  • Posts: 422
    • View Profile
Re: Bézier Curves (Demo)
« Reply #1 on: July 16, 2021, 03:56:38 am »
nice, it's a parallel projected 3D

I found a similar demo where you can use the mouse to drag the curve:
Code: QB64: [Select]
  1. deflng a-z
  2. const sw = 800
  3. const sh = 600
  4. pi = 4*atn(1)
  5. declare sub circlef(x, y, r, c)
  6.  
  7. n = 8
  8. dim x(n), y(n)
  9.  
  10. x(0) = 0: y(0) = -200
  11. x(1) = -130: y(1) = -130
  12. x(2) = -200: y(2) = 0
  13. x(3) = -30: y(3) = 30
  14. x(4) = 0: y(4) = 200
  15. x(5) = 230: y(5) = 230
  16. x(6) = 200: y(6) = 0
  17. x(7) = 130: y(7) = -30
  18. 'x(n) = x(0)
  19. 'y(n) = y(0)
  20.  
  21. 'for i=0 to n-1
  22. '       x(i) = 200*cos(2*pi*i/n)
  23. '       y(i) = 200*sin(2*pi*i/n)
  24. 'next
  25.  
  26. 'screenres sw, sh, 32
  27. screen _newimage(sw, sh, 32)
  28. redraw = -1
  29. drag = 0
  30.         'm = getmouse(mx, my, mw, mb)
  31.         do
  32.                 mx = _mousex
  33.                 my = _mousey
  34.                 mb = -_mousebutton(1)
  35.         loop while _mouseinput
  36.  
  37.         if drag then
  38.                 if mb = 1 then
  39.                         x(ii) = mx - sw/2
  40.                         y(ii) = sh/2 - my
  41.                 else
  42.                         drag = 0
  43.                 end if
  44.         else
  45.                 dmin = 1e10
  46.                 for i=0 to n - 1
  47.                         dx = (mx - sw/2) - x(i)
  48.                         dy = (sh/2 - my) - y(i)
  49.                         d = (dx*dx + dy*dy)
  50.                         if d < dmin then
  51.                                 dmin = d
  52.                                 ii = i
  53.                         end if
  54.                 next
  55.  
  56.                 if mb = 1 then
  57.                         omx = mx
  58.                         omy = my
  59.                         drag = -1
  60.                 end if
  61.         end if
  62.  
  63.  
  64.         redraw = -1
  65.  
  66.         if redraw then
  67.                 'screenlock
  68.                 line (0,0)-(sw,sh),_rgb(0,0,0),bf
  69.                 locate 1,1: ? m, mx, my, mw, mb
  70.  
  71.  
  72.  
  73.                 dim t as double, bx as double, by as double
  74.                 pset (sw/2 + x(0), sh/2 - y(0)), _rgb(0,255,0)
  75.                 for t=0 to 1 step 0.01
  76.                         bx = 0
  77.                         by = 0
  78.  
  79.                         for i=0 to n-1
  80.                                 bin = 1
  81.                                 for j=1 to i
  82.                                         bin = bin*(n - j)/j
  83.                                 next
  84.  
  85.                                 bx = bx + bin*((1 - t)^(n - 1 - i))*(t^i)*x(i)
  86.                                 by = by + bin*((1 - t)^(n - 1 - i))*(t^i)*y(i)
  87.                         next
  88.  
  89.                         line -(sw/2 + bx, sh/2 - by), _rgb(0,255,0)
  90.                 next
  91.  
  92.  
  93.  
  94.  
  95.                 'x(n) = x(0)
  96.                 'y(n) = y(0)
  97.                 x0 = sw/2 + x(0)
  98.                 y0 = sh/2 - y(0)
  99.                 circlef x0, y0, 8, _rgb(55,55,55)
  100.                 for i=1 to n-1
  101.                         x1 = sw/2 + x(i)
  102.                         y1 = sh/2 - y(i)
  103.                         line (x0, y0)-(x1, y1), _rgb(55,55,55)
  104.                         'line -(sw/2 + cx, sh/2 - cy)
  105.                         circlef x1, y1, 8, _rgb(55,55,55)
  106.                         x0 = x1
  107.                         y0 = y1
  108.                 next
  109.                 circlef sw/2 + x(ii), sh/2 - y(ii), 8, _rgb(255,0,0)
  110.  
  111.                 'screenunlock
  112.                 'screensync
  113.  
  114.                 redraw = 0
  115.  
  116.                 _display
  117.         end if
  118.  
  119. sub circlef(x, y, r, c)
  120.         x0 = r
  121.         y0 = 0
  122.         e = -r
  123.  
  124.         do while y0 < x0
  125.                 if e <=0 then
  126.                         y0 = y0 + 1
  127.                         line (x - x0, y + y0)-(x + x0, y + y0), c, bf
  128.                         line (x - x0, y - y0)-(x + x0, y - y0), c, bf
  129.                         e = e + 2*y0
  130.                 else
  131.                         line (x - y0, y - x0)-(x + y0, y - x0), c, bf
  132.                         line (x - y0, y + x0)-(x + y0, y + x0), c, bf
  133.                         x0 = x0 - 1
  134.                         e = e - 2*x0
  135.                 end if
  136.         loop
  137.         line (x - r, y)-(x + r, y), c, bf
  138.  
  139.  

Offline RhoSigma

  • QB64 Developer
  • Forum Resident
  • Posts: 565
    • View Profile
Re: Bézier Curves (Demo)
« Reply #2 on: July 16, 2021, 04:43:42 am »
Indeed @_vince, that's for sure a very nice demo too. Will take a closer look when home from work, comparing the algorithm behind it with my own, could be interesting.
My Projects:   https://qb64forum.alephc.xyz/index.php?topic=809
GuiTools - A graphic UI framework (can do multiple UI forms/windows in one program)
Libraries - ImageProcess, StringBuffers (virt. files), MD5/SHA2-Hash, LZW etc.
Bonus - Blankers, QB64/Notepad++ setup pack

Offline Jack002

  • Forum Regular
  • Posts: 123
  • Boss, l wanna talk about arrays
    • View Profile
Re: Bézier Curves (Demo)
« Reply #3 on: July 16, 2021, 07:14:02 pm »
Wow, that is so cool
QB64 is the best!