It’s almost Valentine’s Day so once again it’s time to think about how to draw a heart-shaped curve. The post Plot a heart-shaped function in C# shows one method for plotting a fairly complex function.

This example plots the following simpler parametric equations:

As the parameter `t` varies from 0 to 2π, the equations generate X and Y coordinates that trace out the heart-shaped curve.

The following code shows how the program calculates the X and Y coordinates for a particular `t` value.

// The curve's parametric equations. private float X(float t) { double sin_t = Math.Sin(t); return (float)(16 * sin_t * sin_t * sin_t); } private float Y(float t) { return (float)( 13 * Math.Cos(t) - 5 * Math.Cos(2 * t) - 2 * Math.Cos(3 * t) - Math.Cos(4 * t)); }

These methods simply evaluate the parametric equations and return their results.

The following code shows how the program draws the curve.

// Draw the curve on a bitmap. private Bitmap DrawHeart(int width, int height) { Bitmap bm = new Bitmap(width, height); using (Graphics gr = Graphics.FromImage(bm)) { gr.SmoothingMode = SmoothingMode.AntiAlias; // Generate the points. const int num_points = 100; Listpoints = new List (); float dt = (float)(2 * Math.PI / num_points); for (float t = 0; t <= 2 * Math.PI; t += dt) points.Add(new PointF(X(t), Y(t))); // Get the coordinate bounds. float wxmin = points[0].X; float wxmax = wxmin; float wymin = points[0].Y; float wymax = wymin; foreach (PointF point in points) { if (wxmin > point.X) wxmin = point.X; if (wxmax < point.X) wxmax = point.X; if (wymin > point.Y) wymin = point.Y; if (wymax < point.Y) wymax = point.Y; } // Make the world coordinate rectangle. RectangleF world_rect = new RectangleF( wxmin, wymin, wxmax - wxmin, wymax - wymin); // Make the device coordinate rectangle with a margin. const int margin = 5; Rectangle device_rect = new Rectangle( margin, margin, picGraph.ClientSize.Width - 2 * margin, picGraph.ClientSize.Height - 2 * margin); // Map world to device coordinates without distortion. // Flip vertically so Y increases downward. SetTransformationWithoutDisortion(gr, world_rect, device_rect, false, true); // Draw the curve. gr.FillPolygon(Brushes.Pink, points.ToArray()); using (Pen pen = new Pen(Color.Red, 0)) { gr.DrawPolygon(pen, points.ToArray()); } } return bm; }

After some preparation the code loops through 100 values for `t` to generate points on the curve. That part is short and reasonably straightforward. The bulk of this method figures out how to center the resulting curve.

To do that the code first loops through the curve's points to find the minimum and maximum X and Y coordinates. It uses those values to make a rectangle that encloses the points in world coordinates.

Next the method creates a rectangle giving the area in the `PictureBox` where the heart-shaped curve should be placed. The code subtracts a bit to leave a margin around the edges of the `PictureBox`.

The program then calls the `SetTransformationWithoutDisortion` method described in the post Map drawing coordinates without distortion in C# to prepare the `Graphics` object to map the world coordinates to the device coordinates.

Finally the method draws the polygon. The `Graphics` object's transformations automatically make the result fit the `PictureBox` nicely.

Pingback: Draw a 3D heart using WPF and C# - C# HelperC# Helper