home *** CD-ROM | disk | FTP | other *** search
/ Simtel MSDOS 1992 September / Simtel20_Sept92.cdr / msdos / plot / bike31.arc / BIKE31.PAS < prev   
Pascal/Delphi Source File  |  1988-02-20  |  17KB  |  412 lines

  1. {  BIKEGEAR  -   Copyright 1988  by Dave Tutelman.  All rights reserved
  2.       You may:
  3.          - Modify this program for your own use, or
  4.          - Distribute UNMODIFIED copies of the source
  5.            (optionally including the executable),
  6.            provided no charge is made without my written permission.
  7.  
  8.        Dave Tutelman
  9.        16 Tilton Drive
  10.        Wayside, NJ 07712         (201) 922-9576
  11. }
  12.  
  13. {  BIKEGEAR   is a program in Turbo Pascal to plot the gear ratios      }
  14. {     for a given set of sprockets.  It works for up to a 21-speed      }
  15. {     bicycle.  The program is controlled by cursor keys and            }
  16. {     numerics, in an obvious way.                                      }
  17. {                                 Dave Tutelman  11/86                  }
  18.  
  19. {     HISTORY:
  20.       BIKEGEAR  Private use and "a few close friends".  08/85.
  21.       BIKE2     First "publication".  Distributed on usenet 11/86.
  22.       BIKE3     Added cadence charts.  06/87.
  23.       BIKE3.1   Ported to Turbo 4.0.  Significant speedup.  Slight
  24.                 changes of logic. Posted to usenet.  02/88.
  25. }
  26.  
  27.  
  28. program bikegear;
  29.  
  30. uses   DOS,CRT;
  31.  
  32. const  rear  : array [1..7] of integer = (13, 15, 17, 20, 24, 28, 33);
  33.        front : array [1..3] of integer = (52, 40, 26);
  34.        rmax  : integer = 5;    { number of rear sprockets }
  35.        fmax  : integer = 2;    { number of front sprockets }
  36.        quit  : boolean = FALSE;
  37.        done  : boolean = FALSE;
  38.        wheel : integer = 27;   { wheel diameter in inches }
  39.        crow  : integer = 1;    { input cursor row (0=max entry) }
  40.        ccol  : integer = 1;    { input cursor col (1=front, 2=rear) }
  41.        c_lo  : real = 77.0;    { range of acceptable cadence }
  42.        c_hi  : real = 87.0;
  43.        d_lo      = '<';        { display "tracer" characters }
  44.        d_hi      = '>';
  45.        KEY_UP    = 'H';        { what comes after NULL for special keys }
  46.        KEY_DOWN  = 'P';
  47.        KEY_LEFT  = 'K';
  48.        KEY_RIGHT = 'M';
  49.        g1:string[30] = '    Shows GEAR in inches';
  50.        g2:string[30] = '   for each sprocket pair';
  51.        s1:string[30] = '    Shows SPEED in m.p.h.';
  52.        s2:string[30] = '    for low-high cadence';
  53.        c1:string[30] = '  Shading shows speed range';
  54.        c2:string[30] = '  for <low - high> cadence ';
  55. var    r,f   : integer;        { index for sprockets }
  56.        fbig, fsmall, rbig, rsmall : integer;  { biggest & smallest sprockets }
  57.        mode  : char;           { which mode? gear design or cadence charts? }
  58.        o_spd, d_spd, d_col : integer;
  59.                                { display parameters for cadence chart      }
  60.                                {   o_spd = origin speed                    }
  61.                                {   d_spd = speed difference per tickmark   }
  62.                                {   d_col = columns difference per tickmark }
  63.        scrtitle1,scrtitle2 : string[30];
  64.  
  65.  
  66. procedure BELL;
  67.     begin
  68.         write (^G);
  69.     end;
  70.  
  71. function diff : integer;   { COMPUTES MAXIMUM TOOTH DIFFERENCE }
  72.            var    i : integer;
  73.            begin
  74.                fbig:=front[1]; fsmall:=fbig;
  75.                rbig:=rear[1];  rsmall:=rbig;
  76.                for i:=2 to fmax do
  77.                begin
  78.                    if front[i] > fbig then fbig:=front[i];
  79.                    if front[i] < fsmall then fsmall:=front[i];
  80.                end;
  81.                for i:=2 to rmax do
  82.                begin
  83.                    if rear[i] > rbig then rbig:=rear[i];
  84.                    if rear[i] < rsmall then rsmall:=rear[i];
  85.                end;
  86.                diff := fbig - fsmall + rbig - rsmall;
  87.            end;
  88.  
  89. procedure bannerscreen;   { DISPLAY FIRST SCREEN, & CHOOSE MODE }
  90.    { INTERNAL FUNCTION TO INPUT AN INTEGER }
  91.     function GetCadence (xx, yy : integer) : real;
  92.         var    c : char;
  93.                i : integer;
  94.                sum : real;
  95.         begin
  96.           repeat
  97.             gotoxy (xx,yy); write('      '); gotoxy (xx,yy);
  98.             sum := 0;
  99.             repeat
  100.                 c := readKey;
  101.                 if (c>='0') and (c<='9') then
  102.                 begin
  103.                     write (c);
  104.                     sum := 10*sum + integer(c) - integer('0');
  105.                 end;
  106.             until c=^M;
  107.           until (sum>40) and (sum<130);
  108.           GetCadence := sum;
  109.         end;
  110.     var    i : integer;
  111.     begin
  112.          ClrScr;
  113.          HighVideo;
  114.          gotoxy (32,6);  write ('B I K E G E A R');
  115.          gotoxy (23,9);  write ('Copyright  1988  -  Dave Tutelman');
  116.          gotoxy (30,11); write ('All rights reserved');
  117.          LowVideo;
  118.  
  119.          gotoxy (22,18);  write ('Press ');
  120.          HighVideo;       write ('G');
  121.          LowVideo;        write (' for gearing design chart');
  122.          gotoxy (22,19);  write ('Press ');
  123.          HighVideo;       write ('C');
  124.          LowVideo;        write (' for cadence / speed graph');
  125.          gotoxy (22,20);  write ('Press ');
  126.          HighVideo;       write ('S');
  127.          LowVideo;        write (' for design chart with cadence/speed');
  128.          gotoxy (22,24);  write ('Press ');
  129.          HighVideo;       write ('ESC');
  130.          LowVideo;        write (' to quit');
  131.  
  132.          repeat
  133.              mode := ReadKey;
  134.              if mode>='a'  then     { convert to upper case }
  135.                  mode := char (byte(mode) -$20);
  136.              BELL;
  137.          until (mode='G') or (mode='S') or (mode='C')or (mode=^[);
  138.  
  139.          case mode of
  140.            'G':
  141.               begin  scrtitle1:=g1; scrtitle2:=g2;  end;
  142.            'S':
  143.               begin  scrtitle1:=s1; scrtitle2:=s2;  end;
  144.            'C':
  145.               begin  scrtitle1:=c1; scrtitle2:=c2;  end;
  146.            ^[:
  147.               done := TRUE;
  148.          end;
  149.  
  150.          if (mode='S') or (mode='C') then
  151.          begin
  152.              gotoxy (1,22);
  153.              for i:=1 to 24 do
  154.                  write ('          ');
  155.              gotoxy (22,22); write ('Enter your cadence range:');
  156.              gotoxy (27,23); write ('Low  cadence in RPM = ');
  157.              gotoxy (27,24); write ('High cadence in RPM = ');
  158.              c_lo := GetCadence (49,23);
  159.              c_hi := GetCadence (49,24);
  160.          end;
  161.      end;
  162.  
  163. procedure initscreen;   { DRAW INITIAL PART OF WORKING SCREEN }
  164.     begin
  165.         ClrScr;
  166.         HighVideo;
  167.         gotoxy (52,1);  write (scrtitle1);
  168.         gotoxy (52,2);  write (scrtitle2);
  169.         LowVideo;
  170.         gotoxy (57,4);  write ('Press ESC to EXIT');
  171.         gotoxy (52,6);  write (' To change design of bike,');
  172.         gotoxy (52,7);  write ('use cursor keys and numbers.');
  173.         HighVideo;
  174.         gotoxy (64,9);  write ('FRONT  REAR');
  175.         gotoxy (64,10); write ('(',fmax,')    (',rmax,')');
  176.         for f:=1 to fmax do
  177.         begin
  178.             gotoxy (65,10+2*f); write (front [f]);
  179.         end;
  180.         for r:=1 to rmax do
  181.         begin
  182.             gotoxy (72,10+2*r); write (rear [r]);
  183.         end;
  184.         LowVideo;
  185.         gotoxy (52, 12+2*fmax); write ('Wheel Size = ',wheel:2);
  186.         gotoxy (52, 16+2*fmax); write ('Tooth Diff = ',diff:2);
  187.         HighVideo;
  188.     end;
  189.  
  190. procedure plotgear;     { PLOTS THE CURRENT SPROCKET ARRAY }
  191.     var    gear, maxgear, mingear : real;
  192.            s_lo,s_hi : real;   { speeds for low and high cadence }
  193.            scale : real;       { scale factor for display }
  194.            offset : integer;   { subtract scaled value from offset ... }
  195.            row  : integer;     { row on which to plot the point }
  196.            tickmark : string[2];
  197.     begin
  198.         {  First get a good scale factor  }
  199.         maxgear := wheel / rsmall * fbig;
  200.         mingear := wheel / rbig * fsmall;
  201.         scale := 23.0 / (ln(maxgear) - ln(mingear));
  202.         offset := trunc (ln(maxgear) * scale)  + 1;
  203.  
  204.         for f:=1 to fmax do
  205.         for r:=1 to rmax do
  206.         begin
  207.             gear := wheel / rear[r] * front[f];  { definition of GEAR }
  208.           { The next couple of rows are "magic", to get the display pretty. }
  209.           { It displays the gears logarithmically, as they should be.       }
  210.             row := trunc ( ln(gear) * scale * 2.0 );
  211.             if (row mod 2 = 0) then tickmark:='__'  else tickmark:='--';
  212.             row := offset - (row div 2);
  213.             if row>24 then begin  row:=24; tickmark:='__'; end;
  214.             if row<1  then begin  row:=1;  tickmark:='^^'; end;
  215.             if mode='G' then  gotoxy (9*f, row)
  216.                         else  gotoxy (16*f-14, row);
  217.           { Now write something at this carfully computed place on screen }
  218.             if (fmax>1) and (rmax>1) then   { crossing combination? dim }
  219.                 if (f=1) and (r=rmax)  or  (r=1) and (f=fmax)  then lowVideo;
  220.             if mode='G' then write (tickmark,gear:4:1,tickmark)
  221.                 else begin
  222.                     s_lo := gear * c_lo / 336.0;
  223.                     s_hi := gear * c_hi / 336.0;
  224.                     write (tickmark,s_lo:4:1,'-',s_hi:4:1,tickmark);
  225.                 end;
  226.             highVideo;
  227.         end;
  228.     end;
  229.  
  230. procedure PlotCadLine;       { PLOT THE GRAPHICS FOR ONE CADENCE LINE }
  231.     { Based on  Speed in MPH = Gear * RPM / 336 }
  232.     var    gear : real;
  233.            s_lo, s_hi : real;
  234.                         { speeds at low and high cadence }
  235.            is_lo,is_hi : integer; { indices for s_lo & s_hi on speed line }
  236.            speed : integer;   { index along the speed line }
  237.     begin
  238.        { Compute the position on the speed line of the cadence extremes }
  239.         gear := wheel / rear[r] * front[f];
  240.         s_lo := gear * c_lo / 336.0;
  241.         s_hi := gear * c_hi / 336.0;
  242.         is_lo := round (((s_lo - o_spd) * d_col) / d_spd );
  243.         is_hi := round (((s_hi - o_spd) * d_col) / d_spd );
  244.        { Now plot the line }
  245.         for speed:=0 to 40 do
  246.         begin
  247.           { Regular or reverse video? }
  248.                  if (speed < is_lo)  then TextAttr := $07
  249.             else if (speed > is_hi)  then TextAttr := $07
  250.             else                          TextAttr := $70;
  251.           { Draw a "tickmark" on the graph }
  252.                  if (speed > is_hi) and (speed mod d_col = 0)
  253.                                         then write ('+')
  254.             else if (speed > is_hi)     then write (' ')
  255.             else if speed mod d_col = 0 then write ('+')
  256.             else                             write ('-');
  257.         end;
  258.         TextAttr := $07;
  259.     end;
  260.  
  261. procedure plotcadence;   { PLOT A WHOLE CADENCE CHART }
  262.    { INTERNAL: CHOOSE A GOOD SCALE, AND SET o_spd,d_spd, & d_col }
  263.     procedure set_display_parms;
  264.         var    mingear, maxgear, minspeed, maxspeed : real;
  265.                              { min/max gear and speed to display }
  266.                s_min : integer;   { int version of minspeed }
  267.         begin
  268.             mingear := wheel / rbig * fsmall;
  269.             maxgear := wheel / rsmall * fbig;
  270.             minspeed := mingear * c_lo / 336.0;
  271.             maxspeed := maxgear * c_hi / 350.0;
  272.             s_min := round (minspeed);
  273.             case round (maxspeed-minspeed) of
  274.               0..9:
  275.                     begin  o_spd:=s_min; d_spd:=1; d_col:=4;  end;
  276.               10..12:
  277.                     begin  o_spd:=s_min; d_spd:=1; d_col:=3;  end;
  278.               13..15:
  279.                     begin  o_spd:=s_min; d_spd:=2; d_col:=5;  end;
  280.               16..19:
  281.                     begin  o_spd:=s_min; d_spd:=2; d_col:=4;  end;
  282.               20..25:
  283.                     begin  o_spd:=s_min; d_spd:=2; d_col:=3;  end;
  284.               else
  285.                     begin  o_spd:=0;     d_spd:=5; d_col:=5;  end;
  286.             end;
  287.         end;
  288.     var    i,ispd : integer;
  289.            c : char;
  290.     begin
  291.         set_display_parms;
  292.         gotoxy (1,1); write ('  SPEED');
  293.         for i:=0 to 40 do     { put speed headings on columns }
  294.           if (i mod d_col)=0  then
  295.           begin
  296.             ispd := (i div d_col)*d_spd  + o_spd;
  297.             gotoxy (9+i,1); write ((ispd div 10):1);
  298.             gotoxy (9+i,2); write ((ispd mod 10):1);
  299.           end;
  300.         gotoxy (10,24); HighVideo; write(d_lo,' ');
  301.                 LowVideo; write(c_lo:4:1,' RPM ------- ',c_hi:4:1,' RPM ');
  302.                 HighVideo; write(d_hi);
  303.         for f:=1 to fmax do    { plot a line for each gear combination }
  304.         for r:=1 to rmax do
  305.         begin
  306.             gotoxy (1,  (f-1)*rmax + (r-1) +3);  HighVideo;
  307.             if r=1 then  write (front[f]:2)  else write ('  ');
  308.             write ('  ',rear[r],'  ');
  309.             PlotCadLine ;
  310.         end;
  311.     end;
  312.  
  313. procedure getkey;     { GET THE NEXT KEYSTROKE, AND ACT ON IT }
  314.     var    c : char;
  315.            n,i : integer;
  316.            got : boolean;
  317.     begin
  318.         got := FALSE;
  319.         repeat
  320.             gotoxy (58 + ccol*7, 10 + crow*2);
  321.             c :=readKey;
  322.             case c of
  323.               ^[:  { ESC }
  324.                 begin  got:=true; quit:=true;  end;
  325.               '0'..'9':  { input a new value }
  326.                   begin
  327.                       n := integer (c) - 48;  { ASCII to integer }
  328.                       if (crow=0) and (ccol=1) then     { new fmax }
  329.                           if (n>0) and (n<=3) then
  330.                           begin
  331.                               write (c);
  332.                               fmax := n;
  333.                               for i:=fmax+1 to 3 do
  334.                                   begin gotoxy(65,12+2*i); write('  '); end;
  335.                               got := TRUE;
  336.                       end
  337.                           else BELL;
  338.                       if (crow=0) and (ccol=2) then     { new rmax }
  339.                           if (n>0) and (n<=7) then
  340.                           begin
  341.                               write (c);
  342.                               rmax := n;
  343.                               for i:=rmax+1 to 6 do
  344.                                   begin gotoxy(72,12+2*i); write('  '); end;
  345.                               got := TRUE;
  346.                           end
  347.                           else BELL;
  348.                       if crow>0 then   { new sprocket value, get next digit }
  349.                       begin
  350.                           write (c);
  351.                           c := readKey;   { get next character }
  352.                           if (c>='0') and (c<='9') then   { yup, a digit }
  353.                           begin
  354.                               n := 10*n + integer(c) - 48;
  355.                               if (ccol=1) and (crow=fmax+1) then wheel:=n;
  356.                               if (ccol=1) and (crow<=fmax)
  357.                                         then front [crow] := n;
  358.                               if ccol=2 then rear  [crow] := n;
  359.                               got := TRUE;   { leave getkey and replot }
  360.                           end
  361.                           else begin BELL; got:=TRUE; end;
  362.                       end;
  363.                   end;
  364.               ^L:  { Repaint screen }
  365.                   got := TRUE;
  366.               else
  367.                 if integer(c)=0 then  { beginning of control key sequence }
  368.                 begin
  369.                     c := readKey;
  370.                     case c of
  371.                       KEY_UP:  { arrow up }
  372.                           if crow=0 then BELL
  373.                           else crow := crow-1;
  374.                       KEY_DOWN:  { arrow down }
  375.                           begin
  376.                               if ccol=1 then if crow=fmax+1 then BELL
  377.                                                       else crow := crow+1;
  378.                               if ccol=2 then if crow=rmax then BELL
  379.                                                       else crow := crow+1;
  380.                           end;
  381.                       KEY_LEFT:  { arrow left }
  382.                           if (ccol=1) or (crow>fmax+1) then BELL  else ccol:=1;
  383.                       KEY_RIGHT:  { arrow right }
  384.                           if (ccol=2) or (crow>rmax) then BELL  else ccol:=2;
  385.                       else BELL;
  386.                     end;
  387.                 end
  388.                 else BELL;
  389.             end;
  390.         until got;
  391.     end;
  392.  
  393.  
  394. { Main program is pretty trivial. Procs do all the work. }
  395. begin
  396.     done :=FALSE;
  397.     repeat
  398.         bannerscreen;
  399.         if not done then
  400.         begin
  401.             quit := FALSE;
  402.             repeat
  403.                 initscreen;
  404.                 if mode='C' then plotcadence
  405.                             else plotgear;
  406.                 getkey;
  407.             until quit;
  408.         end;
  409.     until done;
  410.     ClrScr;
  411. end.
  412.