Introduction
A Bezier curve is a curve which is one of the most frequently used for computer graphics. Higher dimensions of Bezier curves are used for 3D works, which also includes Bezier triangle. Pierre Bezier, a fresh engineer who worked for Renault, derived the concept behind the calculative mechanism of the curve, which he used to design automobile body parts. In general, Bezier equations are simple but parametric equations in a variable of t (where t ranges from 0 - 1).
Where are we going to use this?
As a software engineer / programmer, this is a question which we have when we see some irregular mathematical calculations. But the answer is that we use Beziers in almost all graphic related works to draw simple but smooth curves. We use Bezier curves in almost all animations for smooth movement from one point to another in the background. This is widely used in Adobe Flash and Silverlight in their transformation as well.
At times, when you are using 3D animation, Bezier curves are used to define the 3D path and the 2D curves for key frame interpolation.
We also use Bezier if we want to create stretched text, or funny looking faces, as there is a lot of calculation; to be specific, a lot of mathematical calculation in the background which performs these functions.
In this article, I am trying to define a simple Bezier curve (and its points) and find the angle at any given point of the Bezier. This article will help a lot for someone who already has a Bezier curve(s) and want to move an object through it maintaining the rotation of the object.
How did I end up doing this?
I had a requirement where an object path needed to be plotted in a given canvas, and the points needed to be converted into smooth curves. On completing this, I had to move an object (like an arrow) from the starting position to the ending position, maintaining the arrow's rotation angle.
I initially thought it was a screwed up requirement, but as you know, the Wiki has almost all the definitions to calculations. Being an enthusiast in mathematics, I took the challenge to drive through the Bezier curves for a while and ended up with a standard function.
B(t) = (1-t)<sup>2</sup> P0 + 2(1-t) t P1 + t<sup>2</sup>P2 , t ranges from 0,1
This is the function for a Quadratic Bezier curve where P0 is the starting point, P2 is the ending point, and the curve passes through P1. There are various other Bezier curves which can be solved using the given function.
We convert this function into X, Y coordinates as given below:
- B(t)x = (1-t)2 P0x + 2(1-t) t P1x + t2P2x , t ranges from 0,1 (determines the x coordinate of the curve)
- B(t)y = (1-t)2 P0y + 2(1-t) t P1y + t2P2y , t ranges from 0,1 (determines the y coordinate of the curve)
We will be able to get a range of values on substituting values for t(0-1); giving a more precise value for t will give you minute values for x, y coordinates, making it smooth.
Code description
The code is divided into the following blocks:
- Draw a Bezier curve (Silverlight already has this one).
- Find the Bezier coordinates for each part of the curve.
- Determine the angle between the points.
- Draw your arrow.
The System.Windows.Media
namespace already comes with various classes for drawing Bezier segments. They are BezierSegment
(to draw a cubic Bezier curve between two points), PolyBezierSegment
(to draw multiple cubic Bezier curves), QuadraticBezierSegment
(to draw a quadratic Bezier curve), and PolyQuadraticBezierSegment
(to draw a series of Quadratic Bezier curves).
We use the QuadraticBezierSegment
class as given below which will create a Bezier curve for the three points given.
Path p = new Path();
p.Stroke= new SolidColorBrush(Color.FromArgb(100,255,100,255));
p.StrokeThickness= 2;
QuadraticBezierSegment qg = new QuadraticBezierSegment();
qg.Point1 = new Point(Convert.ToDouble(p1x.Text), Convert.ToDouble(p1y.Text));
qg.Point2 = new Point(Convert.ToDouble(p2x.Text), Convert.ToDouble(p2y.Text));
PathFigure pf = new PathFigure();
pf.StartPoint = new Point(Convert.ToDouble(p0x.Text),
Convert.ToDouble(p0y.Text));
pf.Segments.Add(qg);
PathGeometry pg = new PathGeometry();
pg.Figures.Add(pf);
p.Data=pg;
LayoutRoot.Children.Add(p);
We already have a Bezier curve drawn with the above given code; once the curve is drawn, we are going to determine the various points involved in the curve. For my purpose, I only wanted to determine the end point arrow, so I am limiting the value of t from 0.99 to 1 with which I will only get two points (which is required to determine the angle of the arrow).
Note: If you want to find all the points involved in the curve, you should replace the start value from 0.99 to 0, and if you want to go into minute curve points, change the value of increment from 0.01 to any value lesser.
double x = 0, y = 0;
double xold = 0, yold = 0;
double angle = 0;
for (double t = 0.99; t < 1.001; t += 0.01)
{
x = ((1 - t) * (1 - t) * p0.X) + (2 * t * (1 - t) * p1.X) + (t * t * p2.X);
y = ((1 - t) * (1 - t) * p0.Y) + (2 * t * (1 - t) * p1.Y) + (t * t * p2.Y);
x = Math.Round(x, 3);
y = Math.Round(y, 3);
angle = Math.Round(Angle(xold, yold, x, y), 3);
textBox1.Text += "Angle = " + angle.ToString() + "Degrees :" +
x.ToString() + "," + y.ToString() + "\n";
xold = x; yold = y;
}
e
can determine the angle between two different points using geometric functions. This is explained beautifully in the link provided by Carlos Femmer (thank you man): http://www.carlosfemmer.com/post/2006/02/Calculate-Angle-between-2-points-using-C.aspx.
I have used the same function mentioned in the above URL.
The last part of this article is to draw an arrow based on the angle we have determined from the last point of the Bezier curve. I have used a rotateImage
function which does the functionality of rotating an arrow based on the angle. The code below explains the details involved.
Image image = new Image();
Uri uri = new Uri("arrow.jpg", UriKind.Relative);
ImageSource img = new System.Windows.Media.Imaging.BitmapImage(uri);
image.Margin = new Thickness(x, y, 0, 0);
image.SetValue(Image.SourceProperty, img);
image.Width = 36;
image.Height = 32;
image.Stretch = Stretch.Fill;
image.VerticalAlignment = System.Windows.VerticalAlignment.Top;
image.HorizontalAlignment = System.Windows.HorizontalAlignment.Left;
LayoutRoot.Children.Add(image);
private void rotateImage(double angle, Image image1)
{
WriteableBitmap bm;
RotateTransform objTran;
try
{
objTran = new RotateTransform();
objTran.CenterX = 0.5 * image1.Width;
objTran.CenterY = 0.5 * image1.Height;
objTran.Angle = angle;
bm = new WriteableBitmap(image1, objTran);
image1.Source = (System.Windows.Media.ImageSource)bm;
bm = null;
GC.Collect();
}
catch (Exception ex)
{
}
Other variances
We can create variances of Bezier using the formula below:
History
The code does not have much of a history, I just wrote it a couple of days back, but I do have one. Not writing it here as you guys might screw me with your comments.