QB64 Phoenix Edition
Rotating Cylinders in 3D Space - Printable Version

+- QB64 Phoenix Edition (https://qb64phoenix.com/forum)
+-- Forum: QB64 Rising (https://qb64phoenix.com/forum/forumdisplay.php?fid=1)
+--- Forum: Prolific Programmers (https://qb64phoenix.com/forum/forumdisplay.php?fid=26)
+---- Forum: Magdha/Qwerky (https://qb64phoenix.com/forum/forumdisplay.php?fid=69)
+---- Thread: Rotating Cylinders in 3D Space (/showthread.php?tid=4025)



Rotating Cylinders in 3D Space - Magdha - 10-22-2025

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]

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



RE: Rotating Cylinders in 3D Space - bplus - 10-22-2025

+1 cool


RE: Rotating Cylinders in 3D Space - NakedApe - 10-22-2025

Very cool - and way beyond me. +1


RE: Rotating Cylinders in 3D Space - Unseen Machine - 10-22-2025

My thoughts the same, excellent. + 1 from me too!

john