home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / library / dos / mouse / oomouse / bezier.pas < prev    next >
Encoding:
Pascal/Delphi Source File  |  1989-11-26  |  12.0 KB  |  336 lines

  1. program BezierCurves;
  2. { program that demonstrates use of the mouse object and Bezier spline curves }
  3. { Mods: }
  4. { 11-25-89 MAW - Add code to set mouse limits as found by GetMaxX and GetMaxY }
  5. { 11-26-89 MAW - Generalize Bezier Curve for more control points,
  6.                  as determined by max_points. You can make a pretzel
  7.                  10 points, try it!                                    }
  8. uses
  9.   Crt,
  10.   Graph,
  11.   MouseUnit;
  12.  
  13. const
  14.   max_points = 4;            { How many points to handle                }
  15.   radius = 5;                                 { radius of pickup circle }
  16.   resolution = 0.025;        { resolution of Bezier curve approximation }
  17.  
  18. type
  19.   coordinate = record
  20.         row     : integer;
  21.         column  : integer;
  22.   end;
  23.  
  24. var
  25.   OldExitProc   : Pointer;               { Saves exit procedure address }
  26.   last_Bezier_curve : array[1..42] of coordinate; { array size = 1 / resolution + 2 }
  27.   Bezier_fill_pointer : integer;
  28.   mouse         : mouse_object;                          { mouse object }
  29.   MaxX, MaxY    : word;          { The maximum resolution of the screen }
  30.   point         : array[1..Max_Points] of coordinate;
  31.                                  { end and control points       }
  32.  
  33. {-----------------------------------------------------------------------}
  34.  
  35. {$F+} procedure MyExitProc; {$F-}
  36. begin
  37.         ExitProc := OldExitProc;       { Restore exit procedure address }
  38.         CloseGraph;                     { Shut down the graphics system }
  39. end; { MyExitProc }
  40.  
  41. {-----------------------------------------------------------------------}
  42.  
  43. procedure Initialize;
  44. { Initialize graphics and report any errors that may occur }
  45. var
  46.   GraphDriver   : integer;                 { The Graphics device driver }
  47.   GraphMode     : integer;                    { The Graphics mode value }
  48.   ErrorCode     : integer;                { Reports any graphics errors }
  49.   InGraphicsMode : boolean; { Flags initialization of graphics mode }
  50.   PathToDriver   : string;  { Stores the DOS path to *.BGI & *.CHR }
  51.   xasp, yasp : word;
  52. begin
  53.   { when using Crt and graphics, turn off Crt's memory-mapped writes }
  54.   DirectVideo := False;
  55.   OldExitProc := ExitProc;                { save previous exit proc }
  56.   ExitProc := @MyExitProc;                { insert our exit proc in chain }
  57.   PathToDriver := 'c:\lang\bgi';
  58.   repeat
  59.  
  60. {$IFDEF Use8514}                          { check for Use8514 $DEFINE }
  61.     GraphDriver := IBM8514;
  62.     GraphMode := IBM8514Hi;
  63. {$ELSE}
  64.     GraphDriver := Detect;                { use autodetection }
  65. {$ENDIF}
  66.  
  67.     InitGraph(GraphDriver, GraphMode, PathToDriver);
  68.     ErrorCode := GraphResult;             { preserve error return }
  69.     if ErrorCode <> grOK then             { error? }
  70.     begin
  71.       Writeln('Graphics error: ', GraphErrorMsg(ErrorCode));
  72.       if ErrorCode = grFileNotFound then  { Can't find driver file }
  73.       begin
  74.         Writeln('Enter full path to BGI driver or type <Ctrl-Break> to quit:');
  75.         Readln(PathToDriver);
  76.         Writeln;
  77.       end
  78.       else
  79.         Halt(1);                          { Some other error: terminate }
  80.     end;
  81.   until ErrorCode = grOK;
  82.  
  83.   MaxX := GetMaxX;                        { Get screen resolution values }
  84.   MaxY := GetMaxY;
  85.  
  86.   Mouse.ColRange(0,MaxX);                 { Set mouse screen size! }
  87.   Mouse.RowRange(0,MaxY);                 { M. Warot - 11-25-89    }
  88.  
  89.   SetLineStyle ( SolidLn, SolidFill, NormWidth );
  90. end; { Initialize }
  91.  
  92. {-----------------------------------------------------------------------}
  93.  
  94. function adjasp(y : integer) : integer;
  95. begin
  96.         adjasp := (MaxY - y);
  97. end;
  98.  
  99. {-----------------------------------------------------------------------}
  100.  
  101. function pow(x : real; y : word) : real;
  102. { compute x to the y                                                    }
  103. var
  104.   count : word;
  105.   result : real;
  106. begin
  107.         result := 1;
  108.         for count := 1 to y do
  109.                 result := result * x;
  110.         pow := result;
  111. end;
  112.  
  113. {-----------------------------------------------------------------------}
  114.  
  115. function within(x1, y1, x2, y2, radius : integer) : boolean;
  116. { check to see if point is within control point circle                  }
  117. begin
  118.         if (sqrt(abs(sqr(x2 - x1) + sqr(y2 - y1))) <= radius) then
  119.                 within := true
  120.         else
  121.                 within := false;
  122. end;
  123.  
  124. {-----------------------------------------------------------------------}
  125.  
  126. procedure Old_Bezier(t : real; var x, y : integer);
  127. { compute actual Bezier coordinates for 0 <= t <= 1 and current control }
  128. { points.  The Bezier spline curve function is:                         }
  129. {                                                                       }
  130. {                     3              2       2             3            }
  131. {       x(t) = (1 - t) X  + 3t(1 - t) X  + 3t (1 - t)X  + t X           }
  132. {                       0              1              2      3          }
  133. {                                                                       }
  134. {                     3              2       2             3            }
  135. {       y(t) = (1 - t) Y  + 3t(1 - t) Y  + 3t (1 - t)Y  + t Y           }
  136. {                       0              1              2      3          }
  137. {                                                                       }
  138. begin
  139.         x := round(pow(1 - t, 3) * point[1].column +
  140.                 3 * t * pow(1 - t, 2) * point[2].column +
  141.                 3 * t * t * (1 - t) * point[3].column +
  142.                 pow(t, 3) * point[4].column);
  143.         y := round(pow(1 - t, 3) * point[1].row +
  144.                 3 * t * pow(1 - t, 2) * point[2].row +
  145.                 3 * t * t * (1 - t) * point[3].row +
  146.                 pow(t, 3) * point[4].row);
  147. end;
  148.  
  149. {-----------------------------------------------------------------------}
  150. { Newer, more generalize Bezier curve, for any number of control points,
  151.   by M. Warot 11-26-1989                                                }
  152.  
  153. Var
  154.   Binomial : array[1..max_points] of real;
  155. procedure Binomial_Init;
  156. var
  157.   i,j : word;
  158. begin
  159.   for i := 1 to max_points do
  160.     Binomial[i] := 0;
  161.   Binomial[1] := 1.0;
  162.  
  163.   for j := 2 to max_points do
  164.     for i := j downto 2 do
  165.       binomial[i] := binomial[i] + binomial[i-1];
  166. end;
  167.  
  168. procedure Bezier(t : real; var x, y : integer);
  169. var
  170.   a    : word;
  171.   s    : real;
  172.   zz   : real;
  173. begin
  174.   s := 1.0-t;
  175.   zz:= 0;
  176.   for a := 1 to max_points do
  177.     zz := zz + (binomial[a] *
  178.                 pow(t,a-1) *
  179.                 pow(s,max_points-a) *
  180.                 point[a].column);
  181.   x := round(zz);
  182.  
  183.   zz := 0;
  184.   for a := 1 to max_points do
  185.     zz := zz + (binomial[a] *
  186.                 pow(t,a-1) *
  187.                 pow(s,max_points-a) *
  188.                 point[a].row);
  189.   y := round(zz);
  190. end;
  191.  
  192. {-----------------------------------------------------------------------}
  193.  
  194. procedure EraseBezierCurve;
  195. { erase old Bezier curve stored in last_Bezier_curve array              }
  196. var x : integer;
  197. begin
  198.         moveto(last_Bezier_curve[1].column, last_Bezier_curve[1].row);
  199.         for x := 2 to Bezier_fill_pointer do
  200.                 lineto(last_Bezier_curve[x].column, last_Bezier_curve[x].row);
  201. end;
  202.  
  203. {-----------------------------------------------------------------------}
  204.  
  205. procedure DrawBezierCurve;
  206. { calculate, draw and save new Bezier curve                             }
  207. var
  208.         t : real;
  209.         x, y : integer;
  210. begin
  211.         Bezier_fill_pointer := 1;
  212.         moveto(point[1].column, adjasp(point[1].row));
  213.         t := 0;
  214.         while t < 1 do begin
  215.                 { calculate new Bezier coordinates                      }
  216.                 Bezier(t, x, y);
  217.  
  218.                 { draw new Bezier curve                                 }
  219.                 lineto(x, adjasp(y));
  220.                 t := t + resolution;
  221.  
  222.                 { save new coordinate for erase function                }
  223.                 last_Bezier_curve[Bezier_fill_pointer].column := x;
  224.                 last_Bezier_curve[Bezier_fill_pointer].row := adjasp(y);
  225.                 inc(Bezier_fill_pointer);
  226.         end;
  227. end;
  228.  
  229. {-----------------------------------------------------------------------}
  230.  
  231. procedure move_point(point_index : integer);
  232. { redraw Bezier curve as a control point is moved                       }
  233. var
  234.   x             : integer;
  235.   status        : integer;
  236.   mouse_row, mouse_column : integer;
  237.   old_mouse_row, old_mouse_column : integer;
  238. begin
  239.         { initialize "old" mouse positions                              }
  240.         mouse.GetStatus(status, old_mouse_row, old_mouse_column);
  241.         repeat
  242.           { get mouse position                                          }
  243.           mouse.GetStatus(status, mouse_row, mouse_column);
  244.  
  245.           { redraw new Bezier curve only if mouse has been moved        }
  246.           if (mouse_row <> old_mouse_row) or (mouse_column <> old_mouse_column) then begin
  247.             old_mouse_row := mouse_row;
  248.             old_mouse_column := mouse_column;
  249.  
  250.             { hide mouse while updating screen                          }
  251.             mouse.Hide;
  252.  
  253.             { erase old control point and Bezier curve                  }
  254.             setcolor(0);
  255.             circle(point[point_index].column, adjasp(point[point_index].row), radius);
  256.             EraseBezierCurve;                   { erase old curve       }
  257.  
  258.             { set new control point coordinates                         }
  259.             point[point_index].row := adjasp(mouse_row);
  260.             point[point_index].column := mouse_column;
  261.  
  262.             { draw all control points and new curve                     }
  263.             setcolor(GetMaxColor);
  264.             for x := 1 to Max_Points do
  265.                     circle(point[x].column, adjasp(point[x].row), radius);
  266.             DrawBezierCurve;
  267.  
  268.             { show mouse now that updates have been written to screen   }
  269.             mouse.Show;
  270.           end;
  271.  
  272.           { this just prevents mouse run-on when button has been released}
  273.           mouse.GetStatus(status, mouse_row, mouse_column);
  274.         until status and $01 = 0;
  275. end;
  276.  
  277. {-----------------------------------------------------------------------}
  278.  
  279. var
  280.   ch : char;
  281.   done          : boolean;
  282.   status        : integer;
  283.   button_row    : integer;
  284.   button_column : integer;
  285.   i,j           : word;
  286.  
  287. begin
  288.   Binomial_Init;
  289.         { check for mouse driver                                        }
  290.         if not mouse.Exists then begin
  291.                 writeln('Error:  this program requires the use of a mouse');
  292.                 halt(1);
  293.         end;
  294.  
  295.         { initialize graphics system                                    }
  296.         Initialize;
  297.  
  298.         { setup origional Bezier curve control points                   }
  299.         for i := 1 to max_points do
  300.         begin
  301.           Point[i].column := (i * maxX) div (max_points+1);
  302.           Point[i].row    := maxY div 4;
  303.         end;
  304.  
  305.         Point[1].row          := MaxY div 2;
  306.         Point[max_points].row := MaxY div 2;
  307.  
  308.         { draw origional Bezier curve control points                    }
  309.         for i := 1 to max_points do
  310.           circle(point[i].column, adjasp(point[i].row), radius);
  311.  
  312.         { draw origional Bezier curve                                   }
  313.         DrawBezierCurve;
  314.  
  315.         { show mouse pointer                                            }
  316.         if mouse.Exists then mouse.show;
  317.  
  318.         done := false;
  319.         repeat
  320.                 mouse.GetStatus(status, button_row, button_column);
  321.                 { if button one pushed then check if in control point   }
  322.                 if status and $01 <> 0 then
  323.                 begin
  324.                   for i := 1 to max_points do
  325.                     if within(point[i].column, adjasp(point[i].row), button_column, button_row, radius)
  326.                         then move_point(i);
  327.                 end;
  328.  
  329.                 { repeat until ESC pressed                              }
  330.                 if keypressed then begin
  331.                   ch := readkey;
  332.                   if ch = #27 then done := true;
  333.                 end;
  334.         until done;
  335. end.
  336.