In order to pass the last exam left and graduate from the University of Plovdiv I had to create a small program that draws some splines. I picked Bézier curves as they seemed to be one of the simplest kind of parametric curves.
My friend Stoiko researched the algorithms for drawing Bézier curves and implemented one of them in C and OpenGL. After a lot of explanations I was able to understand it and port it to .NET. As it seems this algorithm is an implementation of the de Casteljau's algorithm used in conjuction with linear interpolation to draw the curve.
At first I implemented it as a Windows Forms application but in order to make it more useful to my professor I decided to port the program to Silverlight so it can be used from the course website without downloading any executables. The first step was to separate the algorithm from the drawing and user interface code. This is why I created the class Bezier which has a single public method that looks like this:
public static IEnumerable<Point> GetCurvePoints(List<Point> controlPoints, double step)
{
//make sure the spline goes through the first point
yield return controlPoints[0];
for (double t = step; t <= 1; t += step)
{
yield return LerpSpline(controlPoints, t);
}
//make sure the spline goes through the last point
yield return controlPoints[controlPoints.Count - 1];
}
Just pass in the control points and you will get the points for the spline. The problem is that the LerpSpline method (which is private) does not return the first and the last point which are in fact the first and last control points. I believe that if we need to be mathematically correct the first and the last points are not considered control points but the beginning and the end of the curve. However in order to draw the curve correctly I needed this points. Here you can see how elegantly the yield statement fits in the implementation. There are no checks like:
if(firstCall)
{
firstCall = false;
return controlPoints[0];
}
There is just one logical flow as if we were building a list. This implementation is also lazy and will generate points on demand although my client code does not make use of this. Another cool thing is that the algorithm is highly parallelizable so if we replace the for loop with the Parallel.For from the Task Parallel Library it will make use of multicore processors without any other changes.
This is my first Silverlight application and it caught me by surprise several times. At first I was developing a WPF browser application thinking that it was a Silverlight application. How was I to know that an application that uses XAML, matches the Silverlight documentation and runs in a browser is not Silverlight? Go ahead, laugh at me! Then I had to deal with the lack of double click and right click events in Silverlight. I believe that Microsoft went a bit over the top with the portability aspect here. The explanation is that some platforms (phones?) may not have easy way to right click. There are hacks to implement both double click and right click. Come on Microsoft why do you make us do it? If we do not take care of different clients they will be screwed anyway. Just give us some property telling us if the platform supports right click!
Unlike desktop applications drawing in Silverlight is not done using a Graphics object. Instead you define elements which are added to a control tree much like the HTML DOM. There are elements for curves, shapes, etc. I used the Polyline shape to draw the curve as a series of small lines. If you create a long enough curve (or edit the value of the step in the code) you can actually see the lines. I had to define several brushes for the different colors because the Silverlight runtime does not contain the predefined ones that you can use in the full .NET Framework. Many method overloads are also missing because the size of the runtime download is important for the end users so only the most important things are in.
So here is the actual application. You can use Shift + click to add a control point, Ctrl + click to remove a control point and drag points around. By the
way Silverlight 3.0 was released today so I quickly ported the application and although it does not use any of the new features you need to have the latest
Silverlight runtime. It is fast and painless download and install experience which takes less than a minute and does not require browser restart.
I hope that I will find the time to extend the application with features or someone else will contribute something. If you are interested in contributing or just looking at the code you can download it here. From mathematical point of view one can contribute by adding other kinds of curves or features for splitting the curve. From the point of view of software development one can add GUI for controlling the step, features for drawing multiple curves in different colors, displaying coordinates of the control points, saving and loading from file, out of browser installation (Hooray for Silverlight 3.0!) and many more.
This application is a kind of proof of my theory about the strategic value of Silverlight. While Microsoft would undoubtedly be happy if Silverlight dethroned Flash in the RIA world I doubt they expect it. However Silverlight makes .NET more complete platform. If you are a .NET developer and you need RIA functionality you can just go ahead and use Silverlight using your current skill set. If I had to port this application to Flash in order to make a RIA version I would have stopped with the desktop version. Similarly if a company needs some RIA functionality in a .NET project it can use Silverlight. In the past it would need to hire a Flash developer just for a small part of the project which would cost more. Now that we have Silverlight we (.NET developers) are kind of self-sufficient. In my opinion the motivation behind JavaFX is pretty much the same.
Thanks a lot to Stoiko for figuring out how to draw Bézier curves programatically and to a guy known by the nickname dragonshed in the ##csharp channel on irc.freenode.org who helped me with some of the Silverlight issues.
Oh, in case anyone was wondering Bézier curves and splines in general are used in vector graphics tools to represent free-form smooth curves and more importantly for defining paths for animated objects in Flash and Silverlight itself.