'============================================================================ ' G.H. George Created 1994 OCT 31 ' LIMACONS.BAS Modified 1998 MAY 01 ' to illustrate the sketching of the family of limacons r = k + cos theta . '============================================================================ ' Procedures: ' IntroScreen: print welcome message ' Axes: draw & label axes for cartesian and polar plots ' DrawGraph: draw polar and cartesian plots ' Increment: adjust the value of k (or quit) DECLARE SUB IntroScreen (k!, Done AS INTEGER) DECLARE SUB Axes (k!) DECLARE SUB DrawGraph (k AS SINGLE) DECLARE SUB PressAnyKey () DECLARE SUB WaitForKey (KeyPressed AS STRING) DECLARE SUB Cartesian (k!) DECLARE SUB Increment (k!, Done AS INTEGER) ' Global constants: ' False: logical false (= 0) ' True: logical true (= -1) ' Pi: pi DEFINT F, T CONST False = 0, True = NOT False CONST Pi = 3.14159265# ' Variables: ' k: current value of offset k in r = k + cos theta . ' Done: logical variable: governs exit from the program. DIM Done AS INTEGER CALL IntroScreen(k, Done) DO CALL Axes(k) CALL Cartesian(k) CALL DrawGraph(k) CALL Increment(k, Done) LOOP UNTIL Done END DEFSNG F, T SUB Axes (k) '============================================================================ ' Enter graphics mode, draw & label axes for both cartesian and polar ' plots. '============================================================================ ' No procedures or local variables. ' Parameters: ' k: value of the offset k in r = k + cos theta SCREEN 7 ' Graphics screen (EGA or VGA needed) COLOR 15 ' v-- title for graphs. LOCATE 1, 1: PRINT "Cartesian and Polar Graphs of" LOCATE 2, 17: PRINT "r ="; k; "+ cos "; CHR$(233) ' 233 = theta COLOR 3, 0 ' cyan f/g, black background. LINE (10, 40)-(310, 40) ' x-axis. LINE (110, 60)-(110, 20) ' y-axis. LINE (10, 42)-(10, 38) ' tick mark x = -pi LINE (60, 42)-(60, 38) ' tick mark x = -pi/2 LINE (160, 42)-(160, 38) ' tick mark x = +pi/2 LINE (210, 42)-(210, 38) ' tick mark x = +pi LINE (260, 42)-(260, 38) ' tick mark x = +3pi/2 LOCATE 7, 2: COLOR 3 ' axis labels PRINT "-"; CHR$(227) ' 227 = pi LOCATE 7, 27: PRINT CHR$(227) LOCATE 5, 39: PRINT CHR$(233) LOCATE 2, 14: PRINT "r" LINE (160, 130)-(270, 130) ' polar axis. LOCATE 17, 38: PRINT CHR$(233); "=0" IF ABS(k) <= .7 THEN CIRCLE (160, 130), 70 ' draw guide circle (unit circle). ELSE CIRCLE (160, 130), 70 / (ABS(k) + .3) ' reduce scale if k is too big. END IF END SUB SUB Cartesian (k) '============================================================================ ' Draw cartesian graph of r = k + cos theta . '============================================================================ ' No procedures ' Parameters: ' k: value of the offset k in r = k + cos theta ' Local Variables: ' pixel: screen x-coordinate (pixel #) ' y: r value; then screen y-coordinate (pixel #) ' x: theta value on Cartesian plot. DIM pixel AS INTEGER COLOR 2, 0 IF ABS(k) > .7 THEN ' Reduce if k is too big. LET y = 40 - 20 * ((k + COS(-Pi)) / (ABS(k) + .3)) * 5 / 6 ELSE LET y = 40 - 20 * (k + COS(-Pi)) * 5 / 6 END IF ' 5/6 because of the aspect ratio. PSET (10, y) FOR pixel = 10 TO 310 LET x = (pixel - 110) * Pi / 100 LET y = k + COS(x) IF ABS(k) > .7 THEN y = y / (ABS(k) + .3) ' Reduce scale if k is too big. LET y = 40 - 20 * y * 5 / 6 ' Convert y to pixel #. LINE -(pixel, y) ' Origin at pixel (110, 40) NEXT pixel END SUB SUB DrawGraph (k AS SINGLE) '============================================================================ ' Draw the polar curve, 1.8 degrees at a time. '============================================================================ ' Subprograms: ' WaitForKey: pause until the user presses any key. ' Parameters: ' k: value of the offset k in r = k + cos theta ' Local Variables: ' pixel screen x-coordinate for cartesian plot. ' Upper maximum screen x-coordinate. ' r current distance of curve from pole. ' rc pixel radius of [unit] guide circle. ' xp screen x-coordinate for polar plot. ' yp screen y-coordinate for polar plot. ' yc screen y-coordinate for cartesian plot. ' theta polar coordinate theta. ' oldxp previous value of xp. ' oldyp previous value of yp. ' rColour colour of polar curve (r<0 red, else white). ' KeyPressed the most recent key pressed by user. ' Delay dummy loop counter, used to slow execution down. DEFINT A-Z DIM r AS SINGLE, rc AS SINGLE, theta AS SINGLE, KeyPressed AS STRING LET pixel = 10 ' Start at theta = -pi. CALL WaitForKey(KeyPressed) LET Upper = 310 LET r = k - 1 ' initial r = k + cos(-pi) LET rc = 70 IF ABS(k) > .7 THEN ' If k is too big, scale graph down. LET r = r / (ABS(k) + .3) LET rc = 70 / (ABS(k) + .3) END IF ' Initial values for (r,theta) & (x,y). LET xp = 160 - 70 * r LET yp = 130 LET yc = 40 - 20 * r * 5 / 6 CIRCLE (pixel, yc), 1, 6 ' Indicate current theta on cartesian plot. LET theta = -Pi ' Start at theta = -pi. DO WHILE pixel < Upper CIRCLE (160 + rc * COS(theta), 130 - rc * SIN(theta) * 5 / 6), 1, 3 ' Erase old (r,theta) indicator on unit circle. LET oldxp = xp ' Remember existing polar coord. LET oldyp = yp LET pixel = pixel + 1 ' Proceed to next theta. LET theta = (pixel - 110) * Pi / 100 LET r = k + COS(theta) ' Update (r,theta). ' If k too big, scale graph down. IF ABS(k) > .7 THEN LET r = r / (ABS(k) + .3) LET xp = 160 + 70 * r * COS(theta) ' Update graphics coord. (polar plot) LET yp = 130 - 70 * r * SIN(theta) * 5 / 6 ' (5/6 due to aspect ratio). LET yc = 40 - 20 * r * 5 / 6 IF r < 0 THEN LET rColour = 6 ELSE LET rColour = 7 'Arc colour brown for r<0, white for r>=0. CIRCLE (pixel, yc), 1, rColour ' Draw new circle on Cartesian plot. CIRCLE (160 + rc * COS(theta), 130 - rc * SIN(theta) * 5 / 6), 1, 14 ' Draw new (r,theta) indicator. IF r < 0 THEN LET rColour = 12 ELSE LET rColour = 15 'Arc colour red for r<0, bright white for r>=0. LINE (oldxp, oldyp)-(xp, yp), rColour ' Draw arc. PSET (xp, yp), 2 ' Highlight current (r,é). IF KeyPressed = "N" THEN FOR Delay = 1 TO 5000: NEXT Delay ' Slow plot down IF INKEY$ <> "" THEN LET KeyPressed = "Y" ' Allow user change of mind ELSE CALL WaitForKey(KeyPressed) ' Pause until user ready END IF LOOP COLOR 15 END SUB DEFSNG A-Z SUB Increment (k, Done AS INTEGER) '============================================================================ ' Does the user wish to continue? If so, with what value of k ? '============================================================================ ' Procedures: ' WaitForKey: pause until the user presses any key. ' Parameters: ' k: value of the offset k in r = k + cos theta ' Done: logical variable (= true when the user chooses to quit) ' Local variables: ' KeyPressed: the key most recently pressed by the user ' kNew: [string version of] the value of k entered by the user DIM KeyPressed AS STRING, kNew AS STRING LOCATE 24, 1: PRINT SPC(70); : LOCATE 24, 1 PRINT "Continue (Y) or exit (N)? "; CALL WaitForKey(KeyPressed) IF KeyPressed = "Y" THEN LOCATE 24, 1: PRINT SPC(70); : LOCATE 23, 1: PRINT SPC(70); LOCATE 22, 1 PRINT "Enter new value of k " PRINT "(default = previous value + 0.1 ," PRINT CHR$(34); "B"; CHR$(34); " = previous value - 0.1 ): "; INPUT kNew LOCATE 22, 1 SELECT CASE kNew CASE "-", "B", "b", "P", "p" ' back to previous k LET k = k - .1 CASE "", " ", "A" TO "Z", "a" TO "z" ' forward to next k LET k = k + .1 CASE ELSE ' set new value for k LET k = VAL(kNew) END SELECT CLS ELSE LET Done = True END IF END SUB SUB IntroScreen (k, Done AS INTEGER) '============================================================================ ' Preliminary screen of information to the user. '============================================================================ ' Procedures: ' PressAnyKey: prompt the user to press any key. ' Parameters: ' k: value of the offset k in r = k + cos theta ' Done: logical variable (= true when the user chooses to quit) ' Local variables: ' SCREEN 0: WIDTH 80 CLS PRINT PRINT ' CHR$(128) = C-cedilla PRINT " LIMA"; CHR$(128); "ONS.BAS" PRINT PRINT " Note: this QuickBASIC program requires a monitor capable" PRINT " of supporting graphics in SCREEN 7 (EGA, VGA or better)." PRINT PRINT PRINT " This program will sketch the curve whose equation in polar" PRINT " form is r = k + cos "; CHR$(233); PRINT " starting with k = 0. " PRINT " Each curve will be sketched 1.8 degrees at a time, both in" PRINT " a cartesian sketch of r : "; CHR$(233); PRINT " and a polar sketch of r : "; CHR$(233); " ." PRINT " After drawing each new arc, the program will wait for you" PRINT " to press any key." PRINT PRINT " Press `N' or `n' if you wish to skip to the end of the" PRINT " current sketch." CALL PressAnyKey LET k = 0 ' Begin with circle r = 0 + cos theta . LET Done = False END SUB SUB PressAnyKey '============================================================================ ' Prompts the user to press a key -- program pauses until user complies. '============================================================================ ' Procedures: ' WaitForKey: pause until any key is pressed ' Parameters: ' ' Local variables: ' KeyPressed: the key pressed by the user (not needed here) DIM KeyPressed AS STRING LOCATE 25, 1 PRINT "Press any key to continue: "; CALL WaitForKey(KeyPressed) LOCATE 24, 1 END SUB SUB WaitForKey (KeyPressed AS STRING) '============================================================================ ' Cause the program to pause until any key is pressed. '============================================================================ ' No procedures or local variables. ' Parameters: ' KeyPressed: the key pressed by the user DO LET KeyPressed = UCASE$(INKEY$) LOOP UNTIL KeyPressed <> "" IF ASC(KeyPressed) = 13 OR ASC(KeyPressed) = 32 THEN LET KeyPressed = "Y" ' ^-- treat and as a "YES" response. END SUB