home *** CD-ROM | disk | FTP | other *** search
/ Amiga Format 91 / af091a.adf / af91a3.lzx / prgs / Gfx / BezierLab.b < prev    next >
Text File  |  2018-09-22  |  15KB  |  602 lines

  1. {*
  2. ** Bezier Curve Laboratory.
  3. **
  4. ** Author: David J Benn
  5. **   Date: 29th-31st October 1994,
  6. **       1st-5th November 1994
  7. **
  8. ** Algorithm for CreateBezierSpline subprogram taken (and modified) from a C
  9. ** implementation by Doug McKenna in MacTech magazine, September 1994.  
  10. *}
  11.  
  12. STRING version SIZE 20
  13. version = "$VER: BezierLab 1.0 (05.11.94)"
  14.  
  15. {*
  16. ** Misc. Constants.
  17. *}
  18. CONST nominalIndex = 1
  19. CONST default = -1&
  20. CONST NULL = 0&
  21. CONST true = -1&, false = 0&
  22.  
  23. CONST maxPoints = 16
  24. CONST xmin = 10, xmax = 620
  25. CONST ymin = 5, ymax = 170
  26.  
  27. {*
  28. ** Menu constants.
  29. *}
  30. CONST sDisable    = 0
  31. CONST sEnable    = 1
  32. CONST sCheck    = 2
  33.  
  34. CONST mProject        = 1
  35. CONST iNew        = 1
  36. CONST iAnimate        = 2
  37. CONST iStop        = 3
  38. CONST iFast        = 4
  39. CONST iReposition    = 5
  40. CONST iSep1.1        = 6
  41. CONST iAbout        = 7
  42. CONST iQuit        = 8
  43.  
  44. {*
  45. ** Types.
  46. *}
  47. STRUCT Point2D
  48.   SHORTINT x
  49.   SHORTINT y
  50. END STRUCT
  51.  
  52. {*
  53. ** Globals.
  54. *}
  55. DIM ADDRESS path(maxPoints)
  56. DECLARE STRUCT Point2D p0, c1, c2, p3
  57. SHORTINT theMenu, theItem
  58. SHORTINT c1_deltaX, c1_deltaY, c2_deltaX, c2_deltaY 
  59. LONGINT animate, finished, fast_mode, reposition
  60.  
  61. {*
  62. ** Events.
  63. *}
  64. ON MENU GOSUB handle_menu
  65. MENU ON
  66.  
  67. {*
  68. ** Subprograms.
  69. *}
  70. SUB SetUpMenus
  71.     MENU mProject,0,sEnable,        "Project"
  72.     MENU mProject,iNew,sEnable,        "  New",     "N"
  73.     MENU mProject,iAnimate,sEnable,        "  Animate",     "A"
  74.     MENU mProject,iStop,sEnable,        "  Stop",     "S"
  75.     MENU mProject,iFast,sCheck,        "  Fast",     "F"
  76.     MENU mProject,iReposition,sEnable,    "  Reposition",    "R"
  77.     MENU mProject,iSep1.1,sDisable,        "-------------------"
  78.     MENU mProject,iAbout,sEnable,        "  About..."
  79.     MENU mProject,iQuit,sEnable,        "  Quit",     "Q"
  80. END SUB
  81.  
  82. SUB SetUpPathArray(ADDRESS path_array, SHORTINT numPoints)
  83. {*
  84. ** Allocate memory for numPoints Point2D structures
  85. ** and initialise each array element with these.
  86. *}
  87. DIM ADDRESS path(nominalIndex) ADDRESS path_array 
  88. DECLARE STRUCT Point2D *the_point
  89. SHORTINT i
  90.  
  91.     FOR i=0 TO numPoints
  92.       the_point = ALLOC(SIZEOF(Point2D))
  93.       IF the_point <> NULL THEN 
  94.           path(i) = the_point
  95.       ELSE
  96.         MsgBox "Memory allocation failure. Aborting.", "Continue"
  97.         EXIT SUB
  98.       END IF
  99.     NEXT
  100. END SUB
  101.  
  102. SUB SetInitialCurve(ADDRESS p0_struct, ADDRESS c1_struct, ~
  103.                    ADDRESS c2_struct, ADDRESS p3_struct)
  104. {*
  105. ** Randomly determine curve end points, tension points and
  106. ** motion direction values.
  107. *}
  108. SHARED c1_deltaX, c2_deltaX, c1_deltaY, c2_deltaY 
  109. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3
  110.  
  111.     '..Initialise point2D structures
  112.     p0 = p0_struct
  113.     c1 = c1_struct
  114.     c2 = c2_struct
  115.     p3 = p3_struct
  116.  
  117.     '..Set curve end-points.
  118.     p0->x = CINT(RND*(xmax-xmin))+xmin : p0->y = CINT(RND*(ymax-ymin))+ymin
  119.     p3->x = CINT(RND*(xmax-xmin))+xmin : p3->y = CINT(RND*(ymax-ymin))+ymin
  120.  
  121.     '..Set tension (control) points.
  122.     c1->x = CINT(RND*(xmax-xmin))+xmin : c1->y = CINT(RND*(ymax-ymin))+ymin
  123.     c2->x = CINT(RND*(xmax-xmin))+xmin : c2->y = CINT(RND*(ymax-ymin))+ymin
  124.  
  125.     '..Set random motion directions for each tension point.
  126.     IF RND < .5 THEN c1_deltaX = -1 ELSE c1_deltaX = 1
  127.     IF RND < .5 THEN c2_deltaX = -1 ELSE c2_deltaX = 1
  128.     IF RND < .5 THEN c1_deltaY = -1 ELSE c1_deltaY = 1
  129.     IF RND < .5 THEN c2_deltaY = -1 ELSE c2_deltaY = 1
  130. END SUB
  131.  
  132. SUB CreateBezierSpline(ADDRESS p0_struct, ADDRESS c1_struct, ~
  133.                ADDRESS c2_struct, ADDRESS p3_struct, ~
  134.                ADDRESS path_array, SHORTINT numPoints)
  135. {*
  136. ** Compute the path of a Bezier spline whose starting 
  137. ** and ending knot points are p0 and p3, and whose control 
  138. ** (tension) points are c1 and c2. The path should be stored
  139. ** in the array "path", which is expected to be able to hold
  140. ** (numPoints+1) elements, from 0 to numPoints inclusive. 
  141. ** numPoints should be a power of 2 between 2 and 32, inclusive.
  142. ** This routine can be easily generalised to 3D coordinates, and 
  143. ** is optimised for fast computation in (long) integers. 
  144. ** [Doug McKenna, MacTech, Sept. 1994, pg 72]
  145. *}
  146. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3, *the_point
  147. DIM ADDRESS path(nominalIndex) ADDRESS path_array
  148. LONGINT i, ax,ay, bx,by, cx,cy, curx,cury
  149. SHORTINT s1,s2,s3
  150. SHORTINT old_lastX,old_lastY, new_lastX,new_lastY
  151. SHORTINT old_currX, old_currY
  152.  
  153.     '..Deactivate event trapping.
  154.     MENU STOP
  155.  
  156.     '..Initialise point2D structures
  157.     p0 = p0_struct
  158.     c1 = c1_struct
  159.     c2 = c2_struct
  160.     p3 = p3_struct
  161.  
  162.     curx = p0->x : cury = p0->y    '..Convert to longints
  163.     
  164.     '..Compute the integer Bezier spline cefficients, a, b and c
  165.     cx = (c1->x - curx) : cx = cx + SHL(cx,1)  '..c=3*(c1-p0) 
  166.     cy = (c1->y - cury) : cy = cy + SHL(cy,1)
  167.  
  168.     bx = (c2->x - c1->x)
  169.     bx = bx + (SHL(bx,1) - cx)  '..b=3*(c2-c1)-c
  170.     by = (c2->y - c1->y)
  171.     by = by + (SHL(by,1) - cy)
  172.  
  173.     ax = (p3->x - curx) - cx - bx  '..a=(p3-p0)-c-b
  174.     ay = (p3->y - cury) - cy - by
  175.     
  176.     CASE
  177.       numPoints = 32 : s1 = 5
  178.       numPoints = 16 : s1 = 4
  179.       numPoints =  8 : s1 = 3
  180.       numPoints =  4 : s1 = 2
  181.       default     : s1 = 1
  182.     END CASE
  183.  
  184.     s2 = s1+s1 : s3 = s2+s1  '..s2=2*s1 : s3=3*s1        
  185.  
  186.     {*
  187.     ** Scale operands up for later,
  188.     ** according to the degree in i 
  189.     ** in loop below.
  190.     *}
  191.     bx = SHL(bx,s1) : by = SHL(by,s1)
  192.     cx = SHL(cx,s2) : cy = SHL(cy,s2)
  193.  
  194.     '..s3 is up to 15 bits worth of scaling.
  195.     curx = SHL(curx,s3) : cury = SHL(cury,s3)
  196.  
  197.     {* 
  198.     ** Get i'th path point along curve from p0 to p3
  199.     ** (inclusive) and plot line segment from (i-1)'th 
  200.     ** point to i'th. Line segments associated with the
  201.     ** old curve are erased before each new segment is
  202.     ** plotted.
  203.     *}
  204.     '..Starting point.
  205.     the_point = path(0) : the_point->x = p0->x : the_point->y = p0->y
  206.     old_lastX = the_point->x : old_lastY = the_point->y
  207.     new_lastX = the_point->x : new_lastY = the_point->y
  208.  
  209.     '..Create new curve while erasing old one.
  210.     FOR i=1 TO numPoints
  211.       '..Get address of current point.
  212.       the_point = path(i)
  213.       '..Store current X and Y values.
  214.       old_currX = the_point->x : old_currY = the_point->y  
  215.       '..Calculate new coordinates.
  216.       the_point->x = SHR((i * (i * (i * ax + bx) + cx) + curx),s3)
  217.       the_point->y = SHR((i * (i * (i * ay + by) + cy) + cury),s3)
  218.       '..Erase old and draw new segment?    
  219.       IF old_currX <> the_point->x OR old_currY <> the_point->y OR ~
  220.          old_lastX <> new_lastX OR old_lastY <> new_lastY THEN
  221.         LINE (old_lastX, old_lastY)-(old_currX, old_currY),0
  222.         LINE (new_lastX, new_lastY)-(the_point->x, the_point->y),1
  223.       END IF
  224.       '..Store old coord's for start of next segment removal.
  225.           old_lastX = old_currX : old_lastY = old_currY
  226.       '..Store new coord's for start of next new segment.
  227.       new_lastX = the_point->x : new_lastY = the_point->y
  228.     NEXT
  229.  
  230.     '..Reactivate event trapping.
  231.     MENU ON
  232. END SUB
  233.  
  234. SUB PlotCurve(ADDRESS p0_struct, ADDRESS path_array, SHORTINT numPoints, ~
  235.           SHORTINT color_id)
  236. {*
  237. ** Plot current curve in the specified color.
  238. *}
  239. DECLARE STRUCT Point2D *p0, *the_point
  240. DIM ADDRESS path(nominalIndex) ADDRESS path_array
  241. SHORTINT i, lastX, lastY
  242.  
  243.     p0 = p0_struct
  244.  
  245.     COLOR color_id
  246.     lastX = p0->x : lastY = p0->y
  247.  
  248.     FOR i=1 TO numPoints
  249.       the_point = path(i)
  250.       LINE (lastX, lastY)-(the_point->x, the_point->y)
  251.       lastX = the_point->x : lastY = the_point->y
  252.     NEXT
  253. END SUB
  254.  
  255. SUB ModifyTension(ADDRESS c1_struct, ADDRESS c2_struct)
  256. {*
  257. ** Move both tension points to next location, possibly 
  258. ** changing the direction of motion of one or both
  259. ** tension points (horizontally and/or vertically).
  260. *}
  261. SHARED c1_deltaX, c1_deltaY, c2_deltaX, c2_deltaY 
  262. DECLARE STRUCT Point2D *c1, *c2
  263.  
  264.     c1 = c1_struct
  265.     c2 = c2_struct
  266.  
  267.     '..Move tension points.
  268.     c1->x = c1->x + c1_deltaX
  269.     c2->x = c2->x + c2_deltaX
  270.     c1->y = c1->y + c1_deltaY
  271.     c2->y = c2->y + c2_deltaY
  272.  
  273.     '..Reached a minimum or maximum?
  274.     IF c1->x < xmin OR c1->x > xmax THEN c1_deltaX = -c1_deltaX
  275.     IF c2->x < xmin OR c2->x > xmax THEN c2_deltaX = -c2_deltaX
  276.     IF c1->y < ymin OR c1->y > ymax THEN c1_deltaY = -c1_deltaY
  277.     IF c2->y < ymin OR c2->y > ymax THEN c2_deltaY = -c2_deltaY
  278. END SUB
  279.  
  280. SUB MarkPoints(ADDRESS p0_struct, ADDRESS c1_struct, ~
  281.            ADDRESS c2_struct, ADDRESS p3_struct, ~
  282.            SHORTINT color_id)
  283. {*
  284. ** Mark end and tension points.
  285. *}
  286. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3
  287.  
  288.       p0 = p0_struct
  289.     c1 = c1_struct
  290.     c2 = c2_struct
  291.     p3 = p3_struct
  292.  
  293.       PSET (p0->x,p0->y),color_id
  294.       PSET (c1->x,c1->y),color_id
  295.       PSET (c2->x,c2->y),color_id
  296.       PSET (p3->x,p3->y),color_id
  297. END SUB
  298.  
  299. SUB AnimateMode(LONGINT activate)
  300. {*
  301. ** Set or reset animate mode.
  302. *}
  303. SHARED animate
  304. SHARED p0, c1, c2, p3
  305.  
  306.     IF activate THEN 
  307.         '..Enable Animation Mode.
  308.         animate = true
  309.         MarkPoints(p0, c1, c2, p3, 0)
  310.         MENU mProject,iAnimate,sDisable
  311.         MENU mProject,iStop,sEnable
  312.     ELSE
  313.         '..Disable Animation Mode.
  314.         animate = false
  315.         MarkPoints(p0, c1, c2, p3, 2)
  316.         MENU mProject,iAnimate,sEnable
  317.         MENU mProject,iStop,sDisable
  318.     END IF        
  319. END SUB
  320.  
  321. SUB MakeNewCurve(ADDRESS p0_struct, ADDRESS c1_struct, ~
  322.          ADDRESS c2_struct, ADDRESS p3_struct, ~
  323.          ADDRESS path_array, SHORTINT numPoints)
  324. {*
  325. ** Initialise and plot new Bezier curve and tension/end points.
  326. *}
  327.  
  328.     AnimateMode(false)
  329.  
  330.     CLS
  331.  
  332.     SetInitialCurve(p0_struct, c1_struct, c2_struct, p3_struct)
  333.  
  334.     CreateBezierSpline(p0_struct, c1_struct, c2_struct, p3_struct, ~
  335.                path_array, numPoints)
  336.  
  337.     MarkPoints(p0_struct, c1_struct, c2_struct, p3_struct, 2)
  338. END SUB
  339.  
  340. SUB ToggleFastMode
  341. {*
  342. ** Switch between fast and slow modes.
  343. *}
  344. SHARED fast_mode
  345.  
  346.     IF fast_mode THEN 
  347.         fast_mode=false 
  348.         MENU mProject,iFast,sEnable
  349.     ELSE 
  350.         fast_mode=true
  351.         MENU mProject,iFast,sCheck
  352.     END IF
  353. END SUB
  354.  
  355. SUB plotHandles(SHORTINT color_id)
  356. {*
  357. ** Plot end and tension point handles in the specified color.
  358. *}
  359. SHARED p0, c1, c2, p3
  360.  
  361.     LINE (p0->x-4,p0->y-2)-(p0->x+4,p0->y+2),color_id,b
  362.     LINE (c1->x-4,c1->y-2)-(c1->x+4,c1->y+2),color_id,b
  363.     LINE (c2->x-4,c2->y-2)-(c2->x+4,c2->y+2),color_id,b
  364.     LINE (p3->x-4,p3->y-2)-(p3->x+4,p3->y+2),color_id,b
  365. END SUB
  366.  
  367. SUB LONGINT inHandle(ADDRESS point_struct, SHORTINT point_num, ~
  368.              SHORTINT x, SHORTINT y)
  369. {*
  370. ** Is x,y coordinate inside a handle?
  371. *}
  372. DECLARE STRUCT Point2D *the_point
  373.  
  374.     the_point = point_struct
  375.  
  376.     IF x >= the_point->x-4 AND x <= the_point->x+4 AND ~
  377.        y >= the_point->y-2 AND y <= the_point->y+2 THEN
  378.         inHandle = point_num+1
  379.     ELSE
  380.         inHandle = 0
  381.     END IF 
  382. END SUB
  383.  
  384. SUB ToggleRepositionMode
  385. {*
  386. ** Toggle repositioning mode.
  387. *}
  388. SHARED reposition, animate, fast_mode
  389. SHARED p0, c1, c2, p3, path
  390. SHORTINT n
  391.  
  392.     IF reposition THEN
  393.         '..Switch off repositioning mode.
  394.         reposition = false
  395.  
  396.         '..Reconfigure menu after leaving Reposition Mode.
  397.         FOR n = iNew TO iQuit
  398.           MENU mProject,n,sEnable
  399.         NEXT
  400.         MENU mProject,iStop,sDisable
  401.         IF fast_mode THEN MENU mProject,iFast,sCheck        
  402.         MENU mProject,iSep1.1,sDisable
  403.         
  404.         '..Erase end and tension points/handles.
  405.         PlotHandles(0)    
  406.         PlotCurve(p0, @path, maxPoints, 1)
  407.         MarkPoints(p0, c1, c2, p3, 2)    
  408.     ELSE
  409.         '..Switch on repositioning mode.
  410.         reposition = true
  411.         animate = false
  412.  
  413.         '..Disable all menu items except one.
  414.         FOR n = iNew TO iQuit
  415.             MENU mProject,n,sDisable
  416.         NEXT
  417.         MENU mProject,iReposition,sCheck
  418.  
  419.         '..Draw end and tension points/handles.
  420.         plotHandles(3)
  421.         MarkPoints(p0, c1, c2, p3, 2)
  422.     END IF
  423. END SUB
  424.  
  425. SUB RepositionPoints(ADDRESS p0_struct, ADDRESS c1_struct, ~
  426.              ADDRESS c2_struct, ADDRESS p3_struct, ~
  427.              ADDRESS path_array, SHORTINT numPoints)
  428. {*
  429. ** Allow user to reposition the end and tension points.
  430. *}
  431. SHARED reposition
  432. DECLARE STRUCT Point2D *p0, *c1, *c2, *p3, *second_point, last_p0
  433. DIM ADDRESS path(nominalIndex) ADDRESS path_array
  434. SHORTINT n, mouseX,mouseY, oldMouseX,oldMouseY, pt
  435. SINGLE time0
  436.  
  437.     '..Initialise structure variables.
  438.       p0 = p0_struct
  439.     c1 = c1_struct
  440.     c2 = c2_struct
  441.     p3 = p3_struct
  442.  
  443.     '..Await left mouse button click.
  444.     WHILE reposition AND NOT MOUSE(0):WEND
  445.     '..Debounce button press.
  446.     time0 = TIMER : WHILE reposition AND TIMER < time0+.1:WEND  
  447.         
  448.     oldMouseX = MOUSE(1) : oldMouseY = MOUSE(2)
  449.     
  450.       IF reposition AND MOUSE(0) THEN
  451.       '..Is mouse pointer inside a handle?
  452.       pt = inHandle(p0, 0, oldMouseX, oldMouseY)
  453.       IF pt = 0 THEN pt = inHandle(c1, 1, oldMouseX, oldMouseY)
  454.       IF pt = 0 THEN pt = inHandle(c2, 2, oldMouseX, oldMouseY)
  455.       IF pt = 0 THEN pt = inHandle(p3, 3, oldMouseX, oldMouseY)
  456.  
  457.       '..Remove end/tension points and handles then redraw curve.
  458.       PlotHandles(0)
  459.       MarkPoints(p0, c1, c2, p3, 0)
  460.       PlotCurve(p0, path_array, numPoints, 1)
  461.  
  462.       WHILE reposition AND MOUSE(0) 
  463.         '..Compare new mouse position with old.
  464.         mouseX = MOUSE(1) : mouseY = MOUSE(2)
  465.  
  466.         IF mouseX <> oldMouseX OR mouseY <> oldMouseY THEN
  467.         '..Reached any limits?
  468.         IF mouseX < xmin THEN mouseX = xmin
  469.         IF mouseX > xmax THEN mouseX = xmax
  470.         IF mouseY < ymin THEN mouseY = ymin
  471.         IF mouseY > ymax THEN mouseY = ymax
  472.  
  473.         '..Save p0 (see below).
  474.         last_p0->x = p0->x
  475.         last_p0->y = p0->y
  476.  
  477.               '..Change coordinates?
  478.             CASE
  479.                   pt = 1 : p0->x = mouseX : p0->y = mouseY
  480.                   pt = 2 : c1->x = mouseX : c1->y = mouseY
  481.                   pt = 3 : c2->x = mouseX : c2->y = mouseY
  482.                   pt = 4 : p3->x = mouseX : p3->y = mouseY
  483.             END CASE
  484.  
  485.         {* 
  486.         ** Since p0 is treated as a special case by CreateBezierSpline
  487.         ** check to see whether it has been moved. If so, erase first curve
  488.         ** segment as it would otherwise be missed (by CreateBezierCurve).
  489.         *}
  490.         IF p0->x <> last_p0->x OR p0->y <> last_p0->y THEN
  491.           second_point = path(1)
  492.           LINE (last_p0->x,last_p0->y)-(second_point->x,second_point->y),0
  493.         END IF
  494.  
  495.               '..Redraw curve.
  496.               CreateBezierSpline(p0, c1, c2, p3, path_array, numPoints)
  497.  
  498.         '..Save last (used) mouse position.
  499.         oldMouseX = mouseX : oldMouseY = mouseY
  500.         END IF
  501.       WEND
  502.  
  503.       '..Refresh curve and redraw end and tension points/handles.
  504.       PlotCurve(p0, path_array, numPoints, 1)
  505.       plotHandles(3)
  506.       MarkPoints(p0, c1, c2, p3, 2)
  507.     END IF    
  508. END SUB
  509.  
  510. SUB AboutBox
  511. SHORTINT buttonX, buttonY
  512.  
  513.     WINDOW 9,"About this program...",(220,25)-(420,175),2
  514.     buttonX = SCREEN(5) : buttonY = SCREEN(6)
  515.     buttonTxt$ = "Continue"
  516.     GADGET 255,ON,buttonTxt$,(100-(buttonX*LEN(buttonTxt$))\2-4,125-buttonY\2-2)- ~
  517.                         (100+(buttonX*LEN(buttonTxt$))\2+4,125+buttonY\2+2), ~
  518.                  BUTTON
  519.     COLOR 1
  520.     LOCATE 2
  521.     RESTORE
  522.     REPEAT
  523.       READ text$
  524.       IF text$ <> "END" THEN 
  525.         CASE
  526.         text$ = "BezierLab" : FONT "diamond",20 : STYLE 4
  527.         text$ = "for Karen"     : FONT "ruby",8 : STYLE 2
  528.         default           : FONT "opal",12 : STYLE 0
  529.         END CASE
  530.         PRINT PTAB(100-(WINDOW(12)*LEN(text$))\2);text$
  531.       END IF
  532.     UNTIL text$ = "END"
  533.     DATA "BezierLab","","","version 1.0","","by David J Benn"
  534.     DATA "","for Karen","END"
  535.     GADGET WAIT 255
  536.     GADGET CLOSE 255
  537.     WINDOW CLOSE 9
  538. END SUB
  539.  
  540. SUB Quit
  541. {*
  542. ** Exit program? 
  543. *}
  544. SHARED finished
  545.  
  546.   IF MsgBox("Really leave BezierLab?","Yes","No") THEN finished = true
  547. END SUB
  548.  
  549. {*
  550. ** Main.
  551. *}
  552. WINDOW 1,"Bezier Curve Laboratory",(0,10)-(640,200),22
  553.  
  554. SetUpMenus
  555. SetUpPathArray(@path, maxPoints)
  556.  
  557. RANDOMIZE TIMER
  558.  
  559. MakeNewCurve(p0, c1, c2, p3, @path, maxPoints)
  560.  
  561. finished = false
  562. fast_mode = true
  563. reposition = false
  564.  
  565. REPEAT
  566.   IF animate THEN 
  567.       ModifyTension(c1, c2)
  568.       CreateBezierSpline(p0, c1, c2, p3, @path, maxPoints)
  569.   ELSE
  570.     IF reposition THEN
  571.         RepositionPoints(p0, c1, c2, p3, @path, maxPoints)
  572.     END IF    
  573.   END IF
  574.  
  575.   IF NOT fast_mode THEN SLEEP FOR .02
  576. UNTIL finished
  577.  
  578. MENU OFF
  579.  
  580. WINDOW CLOSE 1
  581. END
  582.  
  583. {*
  584. ** Event handlers.
  585. *}
  586. handle_menu:
  587.   theMenu = MENU(0)
  588.   theItem = MENU(1)
  589.   
  590.   IF theMenu = mProject THEN
  591.         CASE 
  592.         theItem = iNew           : MakeNewCurve(p0, c1, c2, p3, @path, maxPoints)
  593.         theItem = iAnimate     : AnimateMode(true)
  594.         theItem = iStop        : AnimateMode(false)
  595.         theItem = iFast        : ToggleFastMode
  596.         theItem = iReposition     : ToggleRepositionMode
  597.         theItem = iAbout       : AboutBox
  598.         theItem = iQuit           : Quit 
  599.       END CASE
  600.   END IF
  601. RETURN
  602.