10-22-2025, 08:41 AM
This is a program of cylinders moving in 3D space, and makes use of the _MAPTRIANGLE(3D) QB64 statement.
I had an idea to try to do a simple model of a "slinky" falling down a staircase. Essentially the physics of such a model could be easily handled - Newton's laws of motion under gravity and Hooke's law for the spring extensions. I had to thought to do this by a series of connected cylinders in a helical arrangement. It quickly became apparent that the necessary constraints left the problem beyond my abilities. But the program would have required displaying cylinders moving in a 3D space. That bit I could easily do, as the brilliant folks at QB64 have already sorted out the motion of 3D objects with _MAPTRIANGLE(3D). Whichever QB64 guru it was who sorted out the coding behind _MAPTRIANGLE(3D), I should like to shake their hand.
So, to produce this program of moving & rotating cylinders merely required me to get the geometry of a cylinder correct, and that bit I can manage. The cylinders are partially transparent and have circularly-varying hue. They move into and then out of the 3D space in hyperbolic curves and they rotate in two orthogonal directions.
This is a completely useless program - it has no function, except that it demonstrates the marvellous power of _MAPTRIANGLE(3D). Because there is a lot of graphics manipulation (about 250,000 _MAPTRIANGLE operations per second), the program uses 10% CPU of my Core i5 laptop, so you will a good processor and graphics card to run it. I suspect that the program would be immensely more efficient if the graphics manipulations were done as _MEM objects. But my simple coding does the job.
![[Image: Cylinders.jpg]](https://i.ibb.co/vvQnRpNz/Cylinders.jpg)
I had an idea to try to do a simple model of a "slinky" falling down a staircase. Essentially the physics of such a model could be easily handled - Newton's laws of motion under gravity and Hooke's law for the spring extensions. I had to thought to do this by a series of connected cylinders in a helical arrangement. It quickly became apparent that the necessary constraints left the problem beyond my abilities. But the program would have required displaying cylinders moving in a 3D space. That bit I could easily do, as the brilliant folks at QB64 have already sorted out the motion of 3D objects with _MAPTRIANGLE(3D). Whichever QB64 guru it was who sorted out the coding behind _MAPTRIANGLE(3D), I should like to shake their hand.
So, to produce this program of moving & rotating cylinders merely required me to get the geometry of a cylinder correct, and that bit I can manage. The cylinders are partially transparent and have circularly-varying hue. They move into and then out of the 3D space in hyperbolic curves and they rotate in two orthogonal directions.
This is a completely useless program - it has no function, except that it demonstrates the marvellous power of _MAPTRIANGLE(3D). Because there is a lot of graphics manipulation (about 250,000 _MAPTRIANGLE operations per second), the program uses 10% CPU of my Core i5 laptop, so you will a good processor and graphics card to run it. I suspect that the program would be immensely more efficient if the graphics manipulations were done as _MEM objects. But my simple coding does the job.
![[Image: Cylinders.jpg]](https://i.ibb.co/vvQnRpNz/Cylinders.jpg)
Code: (Select All)
'Rotating Cylinders in 3D Space 15/9/25 by Magdha QB64 v2.0
CONST False = 0, True = NOT False, deltaTheta! = 2 * _PI / 200, BannerSizeX% = 1000, BannerSizeY% = 1000
RANDOMIZE (TIMER)
DIM Banners&(20), Dimensions!(20, 8), HasImage%%(20)
'Rad, Length, Phi, Rpos, Gamma, Beta, Beta Rate, Gamma Rate, Rpos Rate
_TITLE "Cylinders"
Start%% = True
C%% = 0
SCREEN _NEWIMAGE(1100, 700, 32)
_DEST 0
COLOR _RGB32(255, 255, 255), _RGB32(0, 50, 0)
CLS
WHILE INKEY$ = ""
_LIMIT 60
FOR K%% = 0 TO 20
IF Dimensions!(K%%, 0) = 0 AND (Start%% OR RND < 0.0005) THEN
'Set Start Conditions for each cylinder
'Make Banner Image
Dimensions!(K%%, 0) = 30 + 30 * RND 'Rad
Dimensions!(K%%, 1) = 50 + 250 * RND 'Length
Dimensions!(K%%, 2) = 2 * _PI * RND 'Phi
Dimensions!(K%%, 3) = 1000 'Rpos
Dimensions!(K%%, 6) = 0.01 + RND * 0.01 'Beta Rate
Dimensions!(K%%, 7) = 0.01 + RND * 0.01 'Gamma Rate
Dimensions!(K%%, 8) = 0.4 + RND * 0.8 'Rpos Rate
TempImg& = _NEWIMAGE(BannerSizeX% + 1, BannerSizeY% + 1, 32)
_DEST TempImg&
COLOR _RGBA32(255, 255, 255, 0), _RGBA32(255, 255, 0, 0)
CLS
IF Start%% AND K%% = 0 THEN
Start%% = False
Dimensions!(K%%, 3) = 750 'Rpos
END IF
SELECT CASE C%%
CASE 0 'Yellow-based
Red0% = 127 + RND * 128
Green0% = 127 + RND * 128
Blue0% = 127 * RND
CASE 1 'Magenta-based
Red0% = 127 + RND * 128
Green0% = 127 * RND
Blue0% = 127 + RND * 128
CASE ELSE 'Cyan-based
Red0% = 127 * RND
Green0% = 127 + RND * 128
Blue0% = 127 + RND * 128
END SELECT
C%% = C%% + 1
IF C%% > 2 THEN C%% = 0
'Colour varies arond the cylinder, but the sin function ensures that there is no visible step at the join
FOR M% = 0 TO BannerSizeY%
Red% = Red0% * SIN(M% * _PI / BannerSizeY%)
Green% = Green0% * SIN(M% * _PI / BannerSizeY%)
Blue% = Blue0% * SIN(M% * _PI / BannerSizeY%)
COLOR _RGBA32(Red%, Green%, Blue%, 220)
LINE (0, M%)-(BannerSizeX%, M%)
NEXT M%
IF HasImage%%(K%%) THEN _FREEIMAGE Banners&(K%%)
Banners&(K%%) = HardwareImage&(TempImg&, True)
HasImage%%(K%%) = True
_DEST 0
ELSEIF Dimensions!(K%%, 0) <> 0 THEN
'Set geometries for diplayed cylinder and then display
Xpos! = Dimensions!(K%%, 3) * COS(Dimensions!(K%%, 2))
Ypos! = Dimensions!(K%%, 3) * SIN(Dimensions!(K%%, 2))
Zpos! = 200 * SQR(1 + ((Dimensions!(K%%, 3) * Dimensions!(K%%, 3)) / 5000)) - 2700
FOR N% = 0 TO 200
'Make cylinder from Banners&() image
Theta! = N% * 2 * _PI / 200
'Dimensions (radius and length different for each cylinder)
z1! = 0 - Dimensions!(K%%, 1)
z2! = Dimensions!(K%%, 1)
z3! = Dimensions!(K%%, 1)
z4! = 0 - Dimensions!(K%%, 1)
x1! = Dimensions!(K%%, 0) * COS(Theta!)
y1! = Dimensions!(K%%, 0) * SIN(Theta!)
x2! = Dimensions!(K%%, 0) * COS(Theta!)
y2! = Dimensions!(K%%, 0) * SIN(Theta!)
x3! = Dimensions!(K%%, 0) * COS(Theta! + deltaTheta!)
y3! = Dimensions!(K%%, 0) * SIN(Theta! + deltaTheta!)
x4! = Dimensions!(K%%, 0) * COS(Theta! + deltaTheta!)
y4! = Dimensions!(K%%, 0) * SIN(Theta! + deltaTheta!)
'zx plane (Beta) rotation
x12! = x1! * COS(Dimensions!(K%%, 5)) + z1! * SIN(Dimensions!(K%%, 5))
z12! = -x1! * SIN(Dimensions!(K%%, 5)) + z1! * COS(Dimensions!(K%%, 5))
x22! = x2! * COS(Dimensions!(K%%, 5)) + z2! * SIN(Dimensions!(K%%, 5))
z22! = -x2! * SIN(Dimensions!(K%%, 5)) + z2! * COS(Dimensions!(K%%, 5))
x32! = x3! * COS(Dimensions!(K%%, 5)) + z3! * SIN(Dimensions!(K%%, 5))
z32! = -x3! * SIN(Dimensions!(K%%, 5)) + z3! * COS(Dimensions!(K%%, 5))
x42! = x4! * COS(Dimensions!(K%%, 5)) + z4! * SIN(Dimensions!(K%%, 5))
z42! = -x4! * SIN(Dimensions!(K%%, 5)) + z4! * COS(Dimensions!(K%%, 5))
y12! = y1!
y22! = y2!
y32! = y3!
y42! = y4!
'xy plane (Gamma) rotation
x13! = x12! * COS(Dimensions!(K%%, 4)) + y12! * SIN(Dimensions!(K%%, 4)) + Xpos!
y13! = -x12! * SIN(Dimensions!(K%%, 4)) + y12! * COS(Dimensions!(K%%, 4)) + Ypos!
x23! = x22! * COS(Dimensions!(K%%, 4)) + y22! * SIN(Dimensions!(K%%, 4)) + Xpos!
y23! = -x22! * SIN(Dimensions!(K%%, 4)) + y22! * COS(Dimensions!(K%%, 4)) + Ypos!
x33! = x32! * COS(Dimensions!(K%%, 4)) + y32! * SIN(Dimensions!(K%%, 4)) + Xpos!
y33! = -x32! * SIN(Dimensions!(K%%, 4)) + y32! * COS(Dimensions!(K%%, 4)) + Ypos!
x43! = x42! * COS(Dimensions!(K%%, 4)) + y42! * SIN(Dimensions!(K%%, 4)) + Xpos!
y43! = -x42! * SIN(Dimensions!(K%%, 4)) + y42! * COS(Dimensions!(K%%, 4)) + Ypos!
z13! = z12! + Zpos!
z23! = z22! + Zpos!
z33! = z32! + Zpos!
z43! = z42! + Zpos!
'Map cylinder to 3D space
_MAPTRIANGLE (BannerSizeX%, BannerSizeY% * (N% + 1) / 200)-(0, BannerSizeY% * (N% + 1) / 200)-(BannerSizeX%, BannerSizeY% * N% / 200), Banners&(K%%) TO(x13!, y13!, z13!)-(x23!, y23!, z23!)-(x43!, y43!, z43!)
_MAPTRIANGLE (0, BannerSizeY% * N% / 200)-(BannerSizeX%, BannerSizeY% * N% / 200)-(0, BannerSizeY% * (N% + 1) / 200), Banners&(K%%) TO(x33!, y33!, z33!)-(x43!, y43!, z43!)-(x23!, y23!, z23!)
NEXT N%
'Move & Rotate Each Cylinder
Dimensions!(K%%, 3) = Dimensions!(K%%, 3) - Dimensions!(K%%, 8) 'Motion
Dimensions!(K%%, 5) = Dimensions!(K%%, 5) + Dimensions!(K%%, 6) 'zx roation
Dimensions!(K%%, 4) = Dimensions!(K%%, 4) + Dimensions!(K%%, 7) 'xy rotation
IF Dimensions!(K%%, 4) > 2 * _PI THEN Dimensions!(K%%, 4) = Dimensions!(K%%, 4) - 2 * _PI
IF Dimensions!(K%%, 5) > 2 * _PI THEN Dimensions!(K%%, 5) = Dimensions!(K%%, 5) - 2 * _PI
IF Dimensions!(K%%, 3) < -1000 THEN
Dimensions!(K%%, 3) = 1000
Dimensions!(K%%, 0) = 0
END IF
END IF
NEXT K%%
_DISPLAY
WEND
SYSTEM
FUNCTION HardwareImage& (ImageName&, Scrap%%)
HardwareImage& = _COPYIMAGE(ImageName&, 33)
IF Scrap%% THEN _FREEIMAGE ImageName&
END FUNCTION

