Curves and Paths

I l @ ve RuBoard

GDI has had Bezier curves and temporary paths for some time. GDI+ expands these capabilities by providing a rich set of functionality for curves and a persistent path object.

The simplest form is the curve drawn from an array of points. The curve is drawn so that it passes through each point on the array. The tension of the curve for any particular point is controlled by the positions of the points on either side of it in the array. The true Bezier curve has two points associated with each node ”a position and a control point. Tension of the curve is determined by the relationship of the control point to the direction of the line.

Listing 3.5.4 illustrates the use of the Graphics.DrawCurve method by creating a set of positions that bounce around in a rectangular area onscreen. A curve, or Cardinal Spline, is drawn along this array of points, and you can select the tension of the curve with a slider.

Listing 3.5.4 DrawCurve.cs: Using the DrawCurve Method
 1: using System;   2: using System.Drawing;   3: using System.Drawing.Drawing2D;   4: using System.Collections;   5: using System.ComponentModel;   6: using System.Windows.Forms;   7: using System.Data;   8:   9: namespace Curves  10: {  11:    /// <summary>  12:    /// This simple object bounces points  13:    /// around a rectangular area.  14:    /// </summary>  15:    class Bouncer  16:    {  17:       int dirx;  18:       int diry;  19:       int X;  20:       int Y;  21:  22:       Size size;  23:  24:       public Bouncer()  25:       {  26:          dirx=diry=1;  27:       }  28:  29:       public void Move()  30:       {  31:          X+=dirx;  32:          Y+=diry;  33:  34:          if(X<=0  X>=size.Width)  35:             dirx*=-1;  36:  37:          if(Y<=0  Y>=size.Height)  38:             diry*=-1;  39:       }  40:  41:       public Point Position  42:       {  43:          get{ return new Point(X,Y);}  44:          set{ X=value.X; Y=value.Y;}  45:       }  46:  47:       public Size Size  48:       {  49:          get{  return size;}  50:          set{ size = value;}  51:       }  52:    }  53:  54:    /// <summary>  55:    /// Summary description for Form1.  56:    /// </summary>  57:    public class Curves : System.Windows.Forms.Form  58:    {  59:  60:       Timer bounce,paint;  61:       TrackBar trk;  62:  63:       Bouncer[] bouncers;  64:  65:       void OnTickBounce(object sender, EventArgs e)  66:       {  67:          foreach(Bouncer b in bouncers)  68:             b.Move();  69:       }  70:  71:       void OnTickPaint(object sender, EventArgs e)  72:       {  73:          Invalidate();  74:       }  75:  76:       public void OnPaint(object sender, PaintEventArgs e)  77:       {  78:          Pen p=new Pen(Color.Red,10);  79:          SolidBrush br=new SolidBrush(Color.Blue);  80:          Point[] points = new Point[bouncers.Length];  81:          int i=0;  82:          // need to translate our bouncers to an array of points  83:          foreach(Bouncer b in bouncers)  84:             points[i++]=b.Position;  85:          //Draw the curve  86:          e.Graphics.DrawCurve(p,points,0,points.Length- 1,(float)trk.Value);  87:          //now draw the nodes in the curve.  88:          foreach(Point pn in points)  89:             e.Graphics.FillEllipse(br,pn.X-5,pn.Y-5,10,10);  90:          p.Dispose();  91:          br.Dispose();  92:       }  93:  94:       public Curves()  95:       {  96:          this.Paint+=new PaintEventHandler(OnPaint);  97:          // A timer to manage the bouncing  98:          bounce=new Timer();  99:          bounce.Interval=5; 100:          bounce.Tick+=new EventHandler(OnTickBounce); 101:          // A timer to manage the painting refresh 102:          paint=new Timer(); 103:          paint.Interval=100; 104:          paint.Tick+=new EventHandler(OnTickPaint); 105:          // Random number generator for initial positions 106:          Random r=new Random(); 107:          // the form initial size 108:          this.Size=new Size(800,600); 109:          //iniialize an array of bouncing points 110:          bouncers = new Bouncer[6]; 111:          for(int i=0;i<6;i++) 112:          { 113:             bouncers[i]=new Bouncer(); 114:             bouncers[i].Position=new Point(r.Next(800),r.Next(600)); 115:             bouncers[i].Size=new Size(800,600); 116:          } 117:          // turn on the timers 118:          bounce.Enabled=true; 119:          paint.Enabled=true; 120:          //create a trackbar for the line tension 121:          trk = new TrackBar(); 122:          trk.Location=new Point(5,25); 123:          trk.Size=new Size(100,20); 124:          trk.Minimum=1; 125:          trk.Maximum=10; 126:          trk.Value=2; 127:          this.Controls.Add(trk); 128:          //and label it nicely for the user 129:          Label lb=new Label(); 130:          lb.Location=new Point(5,5); 131:          lb.Size=new Size(100,20); 132:          lb.Text="Curve tension"; 133:          this.Controls.Add(lb); 134:       } 135: 136:       static void Main() 137:       { 138:          Application.Run(new Curves()); 139:       } 140:    } 141: } 

Compile Listing 3.5.4 with the following command line:

 Csc /t:winexe drawcurve.cs 

The work is done by two timers and a paint handler. Timer #1 (lines 98 and 65 “69) makes the positions of the curve nodes bounce around the screen. Timer #2 (lines 102 and 71 “74) invalidates the screen so that the painting is not done too frequently. The paint handler (lines 76 “90) creates an array of points from the bounce object; sadly, Point is a sealed class so you cannot inherit from it, which would have been useful. Then line 86 draws the curve, the tension of which depends on the position of the TrackBar control. To illustrate where the individual points are, lines 88 and 89 draw them in blue. This demonstration clearly shows how line tension works for the simple curve.

Figure 3.5.3 shows the DrawCurves application running.

Figure 3.5.3. Drawing a curve with tension.

graphics/0305fig03.gif

A Bezier Spline is somewhat different. For each line segment, two points define the start and end of the line, and another two determine the control points that add the line tension and curvature. Listing 3.5.5 shows how a Bezier curve is used.

Listing 3.5.5 Beziercurves.cs: Using the Bezier Curve
 1: using System;   2: using System.Drawing;   3: using System.Drawing.Drawing2D;   4: using System.Collections;   5: using System.ComponentModel;   6: using System.Windows.Forms;   7: using System.Data;   8:   9: namespace Curves  10: {  11:    /// <summary>  12:    /// This simple object bounces points  13:    /// around a rectangular area.  14:    /// </summary>  15:    class Bouncer  16:    {  17:       int dirx;  18:       int diry;  19:       public int X;  20:       public int Y;  21:  22:       Size size;  23:  24:       public Bouncer()  25:       {  26:          dirx=diry=1;  27:       }  28:  29:       public void Move()  30:       {  31:          X+=dirx;  32:          Y+=diry;  33:  34:          if(X<=0  X>=size.Width)  35:             dirx*=-1;  36:  37:          if(Y<=0  Y>=size.Height)  38:             diry*=-1;  39:       }  40:  41:       public Point Position  42:       {  43:          get{ return new Point(X,Y);}  44:          set{ X=value.X; Y=value.Y;}  45:       }  46:  47:       public Size Size  48:       {  49:          get{  return size;}  50:          set{ size = value;}  51:       }  52:    }  53:  54:    /// <summary>  55:    /// Summary description for Form1.  56:    /// </summary>  57:    public class BezierCurves : System.Windows.Forms.Form  58:    {  59:  60:       Timer bounce,paint;  61:  63:       Bouncer[] bouncers;  62:  63:       void OnTickBounce(object sender, EventArgs e)  64:       {  65:          foreach(Bouncer b in bouncers)  66:             b.Move();  67:       }  68:  69:       void OnTickPaint(object sender, EventArgs e)  70:       {  71:          Invalidate();  72:       }  73:  74:       public void OnPaint(object sender, PaintEventArgs e)  75:       {  76:          Pen p=new Pen(Color.Red,10);  77:          p.StartCap=LineCap.DiamondAnchor;  78:          p.EndCap=LineCap.ArrowAnchor;  79:          SolidBrush br=new SolidBrush(Color.Blue);  80:          //Draw the curve  81:          e.Graphics.DrawBezier(p,new Point(550,300),  82:                                  bouncers[0].Position,  83:                                  bouncers[1].Position,  84:                                  new Point(50,300));  85:          //now draw the nodes in the curve.  86:          foreach(Bouncer b in bouncers)  87:             e.Graphics.FillEllipse(br,b.X-5,b.Y-5,10,10);  88:          //and show the relation between the bouncing node  89:          //and the bezier end point  90:          p=new Pen(Color.Black,1);  91:          p.DashStyle=DashStyle.DashDotDot;  92:          e.Graphics.DrawLine(p,bouncers[0].Position,new Point(550,300));  93:          e.Graphics.DrawLine(p,bouncers[1].Position,new Point(50,300));  94:          p.Dispose();  95:       }  96:  97:       public BezierCurves()  98:       {  99:          this.Paint+=new PaintEventHandler(OnPaint); 100:          // A timer to manage the bouncing 101:          bounce=new Timer(); 102:          bounce.Interval=5; 103:          bounce.Tick+=new EventHandler(OnTickBounce); 104:          // A timer to manage the painting refresh 105:          paint=new Timer(); 106:          paint.Interval=100; 107:          paint.Tick+=new EventHandler(OnTickPaint); 108:          // Random number generator for initial positions 109:          Random r=new Random(); 110:          // the form initial size 111:          this.Size=new Size(800,600); 112:          //iniialize an array of bouncing points 113:          bouncers = new Bouncer[2]; 114:          for(int i=0;i<2;i++) 115:          { 116:             bouncers[i]=new Bouncer(); 117:             bouncers[i].Position=new Point(r.Next(800),r.Next(600)); 118:             bouncers[i].Size=new Size(800,600); 119:          } 120:          // turn on the timers 121:          bounce.Enabled=true; 122:          paint.Enabled=true; 123:       } 124: 125:       static void Main() 126:       { 127:          Application.Run(new BezierCurves()); 128:       } 129:    } 130: } 

The meat of this application is substantially similar to that shown in Listing 3.5.4. The points of interest are lines 83 “86, where the Bezier is drawn, and lines 92 “96, which show you how to draw dashed lines. The image shown in Figure 3.5.4 is a screenshot of the application and shows how the Bezier control points are used to add direction and tension to a particular node.

Figure 3.5.4. The Bezier curve in action.

graphics/0305fig04.gif

An array of points can also be used to create a multi-segmented Bezier Spline. The array must have a multiple of four points and is arranged as follows :

Point[0] = Start point of line segment 1

Point[1] = Control point for the start point

Point[2] = Control point for the end point

Point[3] = End point for line segment and start point of line segment 2

Point[4] = Control point for the start point of line segment 2

And so on, giving 4 initial points plus three for each subsequent line segment.

I l @ ve RuBoard


C# and the .NET Framework. The C++ Perspective
C# and the .NET Framework
ISBN: 067232153X
EAN: 2147483647
Year: 2001
Pages: 204

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net