CYCLIC FUNCTIONS

By Gordon Sweet
http://sionet.mysite.wanadoo-members.co.uk/JustBasic.htm

Now for my offering this issue I must start by coming clean and make it clear this program is based very largely on one by another far cleverer than me. You can see it is based on a 15 year old program by another, so you must forgive me if quite frankly I have very little clue how it works fully.

If you ever visit my site you will find I dabble in a number of versions of BASIC, and as such rely a great deal on the expertise of others especially in this and the LB forum. BASIC in various forms has I believe been around now for over 20 years, and being one of the older generation myself, I think it a great shame if all the early programs were to disappear completely from records, because of all the ever rapidly expanding PC technology. So I like to spend much of my time attempting to upgrade many of these old programs to still work under JB and LB if only in memory of the original authors.

So the little I can say about this program is perhaps such to point out my often use of the variables ux and uy to try to centre the windows on screen. Note the rather crude way we are obliged to use with JB to delay the program just before [circle] resulting in a short burst of 100% CPU usage, you can see if you activate Windows Task Manager. The problem is solved with LB by the use a suitable API call. The screen size of the original old UK BBC computer was 1024 x 1280, hence the unusual WindowWidth/Height settings, also the use of xpos. BBC BASIC had a function to set the screen origin other than the usual x=0 and y=0, hence the use of place and goto in [setup]. Note we need to define Pi in JB.

Mathematics experts are very welcome to comment on the program in the Forum

    ' Original program by Robert T.Templeman
    ' BEEBUG magazine March 1991
    nomainwin
    ux = 1 : uy = 1
    if DisplayWidth > 1000 then ux = 120 : uy = 90
    tl$ = "Cyclic Functions - based on a program for the BBC Computer"
    UpperLeftX = 100+ux : UpperLeftY = 20+uy
    WindowWidth = 640 : WindowHeight = 512 ' half BBC screen
    Open tl$ For Graphics_nsb As #c
    opt = 0 : first = 1 : steps = 10
    #c "trapclose [quit]; when leftButtonDown [opts]"
[opts]
    #c "font arial 18 bold; font arial 40 bold; fill 0 0 50"
    #c "backcolor 0 0 50; color green; place 50 240; down"
    #c "\CYCLIC FUNCTIONS"
    #c "color white" : PI = 3.14159
    GoSub [setup] : xpos = 150
    If first = 1 Then delay = 1 Else delay = 0
    X = 65 : Y = 50 : lar = 75 : sma = 37.5 : D = 0 : st = 2.5 : GoSub 
[draw]
    X = 165 : Y = 50 : lar = 50 : sma = 25 : D = 15 : st = 5 : GoSub 
[draw]
    X = 265 : Y = 50 : lar = 15 : sma = 30 : D = 30 : st = 20 : GoSub 
[draw]
    X = 365 : Y = 50 : lar = 49.5 : sma = 33 : D = 45 : st = 2.5 : 
GoSub [draw]
    X = 465 : Y = 50 : lar = 50 : sma = 37.5 : D = 30 : st = 2.5 : 
GoSub [draw]
    X = 565 : Y = 50 : lar = 50 : sma = 45 : D = 25 : st = 2.5 : GoSub 
[draw]
    If opt = 1 Then Close #d
    first = 0
    UpperLeftX = 270+ux : UpperLeftY = 450+uy
    WindowWidth = 340 : WindowHeight = 80
    Button #d, "DESIGN", [desin], UL 40, 10
    Button #d, "DETAIL", [param], UL 140, 10
    Button #d, " QUIT ", [quit], UL 240, 10
    Open "SELECT OPTION " For Dialog As #d
    Print #d, "trapclose [hold]"
[hold] opt = 1 : Beep :  #c "flush" : Wait

[param]
    opt = 0 : Close #d : GoSub [alter]
    GoTo [opts]

[desin]
    opt = 0 : Close #d : #c "fill 0 0 50"
    X = 256 : Y = 256 : rad = 225 : GoSub [circle]
    X = 256 : Y = 381 : rad = 100 : GoSub [circle]
    X = 210 : Y = 310 : rad = 10 : GoSub [circle]
    X1 = 256 : Y1 = 256 : X2 = 481 : Y2 = 256 : GoSub [arrow]
    X1 = 256 : Y1 = 381 : X2 = 356 : Y2 = 381 : GoSub [arrow]
    X1 = 256 : Y1 = 256 : X2 = 481 : Y2 = 256 : GoSub [arrow]
    X1 = 210 : Y1 = 310 : X2 = 256 : Y2 = 381 : GoSub [arrow]
    #c "font arial 10; place 300 220" : #c "\small radius"
    #c "place 360 120" : #c "\large radius"
    #c "place 320 160" : #c "\distance D"

[box3] If bx=1 Then Close #3
    UpperLeftX = 320+ux: UpperLeftY = 370+uy
    WindowWidth = 220: WindowHeight = 160
    Statictext #3 "Cyclic Functions", 10, 45, 44, 30
    Statictext #3, "Large Radius", 52, 10, 44, 30
    Statictext #3, "Small Radius", 102, 10, 44, 30
    Statictext #3, "Distance D", 140, 20, 70, 30
    Textbox #3.tbox1, 58, 50, 30, 25
    Textbox #3.tbox2, 100, 50, 30, 25
    Textbox #3.tbox3, 142, 50, 30, 25
    Button #3.default, "Accept", [pass3], UL, 90, 90, 42, 25
    Open "Accept or press Enter" For Dialog As #3
    Print #3, "trapclose [npass3]": bx=1
    Print #3.tbox1, "!setfocus"
[npass3] Beep : Wait
[pass3]
    Print #3.tbox1, "!contents? A$" : lrad=Val(A$)
    Print #3.tbox2, "!contents? B$" : srad=Val(B$)
    Print #3.tbox3, "!contents? C$" : d=Val(C$)
    If lrad=0 or srad=0 or d=0 Then Notice "INVALID!" : GoTo [npass3]
[bfin3] bx=0 : Close #3

    #c "fill 0 0 50"
    If srad > lrad Then tempstep = 10 * steps Else tempstep = steps
    X = 512 : Y = 512 : lar = lrad
    sma = srad : D = d : st = tempstep
    xpos = 50 : delay = 1 : GoSub [draw]
    #c "place 220 20; color green"
    #c "\LEFT click to Continue. Points = ";points
    #c "color white" : Wait

[draw]
    Max = lar
    If sma > lar Then Max = sma
    For N = 1 TO Max
        Q = N * lar/sma
        If Q = Int(Q) Then
            points = Q
            R = N
            N = Max
        End If
    Next N
     ' reset screen origin to X & Y
    se = PI * R/(st * points)
    an = 2 * PI * R + se
    I = lar - sma
    R = lar/sma - 1
    #c "place ";(I-D+X)/2+xpos;" ";Y/2
    For T = 0 TO an STEP se
        #c "goto ";(I*Cos(T)-D*Cos(T*R)+X)/2+xpos;" 
";(I*Sin(T)+D*Sin(T*R)+Y)/2
        tim = Time$("ms")
        While Time$("ms") < tim + delay : Wend
        Scan ' allow for QUIT
    Next T
    ' return to normal origin
    Return

[circle]
     ' reset screen origin to X & Y
    #c "place ";(rad+X)/2+200;" ";Y/2
    se = 2.2/Sqr(rad)
    For T=0 TO 6.4 STEP se
        #c "goto ";(rad*Cos(T)+X)/2+200;" ";(rad*Sin(T)+Y)/2
    Next T
    ' return to normal origin
    Return

[arrow]
    TH = Atn((Y1-Y2)/(X1-X2))
    #c "place ";(X1+30*Cos(TH+PI/4))/2+200;" ";(Y1+30*Sin(TH+PI/4))/2
    #c "goto ";X1/2+200;" ";Y1/2
    #c "goto ";(X1+30*Cos(TH-PI/4))/2+200;" ";(Y1+30*Sin(TH-PI/4))/2
    #c "place ";X1/2+200;" ";Y1/2
    #c "goto ";X2/2+200;" ";Y2/2
    #c "place ";(X2-30*Cos(TH-PI/4))/2+200;" ";(Y2-30*Sin(TH-PI/4))/2
    #c "goto ";X2/2+200;" ";Y2/2
    #c "goto ";(X2-30*Cos(TH+PI/4))/2+200;" ";(Y2-30*Sin(TH+PI/4))/2
    Return

[alter]
    tx$ = "Increasing the accuracy of the shape will result"
    tx$ = tx$ + " in a smoother curve being drawn. "
    tx$ = tx$ + "This will however slow the program down. "
    tx$ = tx$ + "Default value is 10. Current value is ";steps;"."
    txi$ = "Enter new step (RETURN=default)"
    UpperLeftX = 170+ux : UpperLeftY = 380+uy
    WindowWidth = 500: WindowHeight = 150
    Statictext #a, tx$, 30, 20, 480, 60
    Statictext #a, txi$, 60, 80, 150, 30
    Textbox #a.tbox1, 220, 85, 30, 20
    Button #a.default, "Accept", [pass], UL, 300, 80, 60, 30
    Open "Click ACCEPT or press Enter" For Dialog As #a
    #a "trapclose [nopass]" : #a "font fixedsys"
    Print #a.tbox1, "!setfocus"
[nopass]
    Beep : Wait
[pass]
    Print #a.tbox1, "!contents? A$" : steps = Val(A$)
    If steps < 1 Then steps = 10
    Close #a
    Return

[setup]
    #c "place ";0;" ";400 : #c "goto ";640;" ";400
    #c "place ";0;" ";60 : #c "goto ";640;" ";60
    Return

[quit]
    T = an  ' close T loop
    If opt = 1 Then Close #d
    If bx = 1 Then Close #3
    Close #c : End