Title: Draw cylinders using WPF and C#
This example shows how to draw cylinders in a WPF application. Other examples such as Create a 3D surface very quickly with WPF, XAML, and C# show how to draw 3D graphics.
This example merely adds the following AddCylinder method to create the necessary points and triangles to make a cylinder.
// Add a cylinder.
private void AddCylinder(MeshGeometry3D mesh,
Point3D end_point, Vector3D axis, double radius, int num_sides)
{
// Get two vectors perpendicular to the axis.
Vector3D v1;
if ((axis.Z < -0.01) || (axis.Z > 0.01))
v1 = new Vector3D(axis.Z, axis.Z, -axis.X - axis.Y);
else
v1 = new Vector3D(-axis.Y - axis.Z, axis.X, axis.X);
Vector3D v2 = Vector3D.CrossProduct(v1, axis);
// Make the vectors have length radius.
v1 *= (radius / v1.Length);
v2 *= (radius / v2.Length);
// Make the top end cap.
double theta = 0;
double dtheta = 2 * Math.PI / num_sides;
for (int i = 0; i < num_sides; i++)
{
Point3D p1 = end_point +
Math.Cos(theta) * v1 +
Math.Sin(theta) * v2;
theta += dtheta;
Point3D p2 = end_point +
Math.Cos(theta) * v1 +
Math.Sin(theta) * v2;
AddTriangle(mesh, end_point, p1, p2);
}
// Make the bottom end cap.
Point3D end_point2 = end_point + axis;
theta = 0;
for (int i = 0; i < num_sides; i++)
{
Point3D p1 = end_point2 +
Math.Cos(theta) * v1 +
Math.Sin(theta) * v2;
theta += dtheta;
Point3D p2 = end_point2 +
Math.Cos(theta) * v1 +
Math.Sin(theta) * v2;
AddTriangle(mesh, end_point2, p2, p1);
}
// Make the sides.
theta = 0;
for (int i = 0; i < num_sides; i++)
{
Point3D p1 = end_point +
Math.Cos(theta) * v1 +
Math.Sin(theta) * v2;
theta += dtheta;
Point3D p2 = end_point +
Math.Cos(theta) * v1 +
Math.Sin(theta) * v2;
Point3D p3 = p1 + axis;
Point3D p4 = p2 + axis;
AddTriangle(mesh, p1, p3, p2);
AddTriangle(mesh, p2, p3, p4);
}
}
The parameters to the method are:
- mesh — The MeshGeometry3D object that should contain the cylinder.
- end_point — The center of one end of the cylinder.
- axis — A vector that determines the direction and length of the cylinder. In other words, the vector connecting the cylinder's two end points.
- radius — The cylinder's radius.
- num_sides — The number of sides the end caps for the cylinder should have. The end caps will each be made up of num_sides triangles. The cylinder's sides will be made up of 2 × num_sides triangles forming num_sides rectangles.
When it begins, the AddCylinder method finds two vectors that are perpendicular to the cylinder's axis and to each other. Those vectors (and all other vectors that are perpendicular to the axis) lie in the plane containing the cylinder's first end cap.
To find the two vectors, the program first creates vector v1. If the axis's Z coordinate is not close to 0, then the vector <axis.Z, axis.Z, -axis.X - axis.Y> is perpendicular to axis. If the axis's Z coordinate is close to 0, then the vector <-axis.Y - axis.Z, axis.X, axis.X> is perpendicular to axis. (To see why those are perpendicular vectors, calculate the dot product of the two vectors. For information about the dot product, see this Wikipedia article.)
Next the method takes the cross product of the first perpendicular vector and the axis. That gives a new vector perpendicular to both of the others (v1 and axis). (To learn why, see this Wikipedia article.)
Now the program has two perpendicular vectors in the plane of the cylinder's end cap. To generate points along the edges of the end cap, the program will use those vectors multiplied by sines and cosines of angles much as you might generate the points on a circle in two dimensions. To give the end cap the right radius, the program divides v1 and v2 by their lengths and multiplies them by radius.
Now the program can start calculating points. To make the top, it makes variable theta range from 0 to 2π. For each value of theta, the program adds the end_point to v1 times sine(theta) plus v2 times cosine(theta). The triangles it uses to build the end cap connect end_point and two adjacent points along the edge of the circle.
The code then makes the bottom similarly. The only difference is that the code reverses the ordering of the three points so the bottom triangle is outwardly oriented. (So WPF can tell which side is on the inside of the cylinder.)
Finally the method makes the cylinder's sides. To do that, the code loops through the values of theta one last time. For each value, it generates points p1 and p2 on the edge of the first end cap. It then adds the vector axis to those points to get the two corresponding points p3 and p4 on the other end cap. Finally it uses those points to make two rectangles between them.
Download the example and look at the code to see how the program uses the AddCylinder method to draw cylinders.
You can increase num_points to draw cylinders more smoothly, but don't get too carried away. In my next post I'll show how you can make the sides of the cylinder look smoother without making num_points huge.
Download the example to experiment with it and to see additional details.
|