Title: Make a bobblehead in C#
The example Draw a bigheaded politician in C# shows how to draw a person with a really big head. To make the program work, you need to separate the person's head and body. The program then positions the head.
If that were all the program did, it would be a lot easier to just use Photoshop or even MS Paint to just make the picture. The real reason I made that program was in preparation for this one, which makes the images act like a bobblehead.
There are actually several ways to physically make a bobblehead, but for our purposes you can pretend that the head is attached to a relatively floppy spring as shown in Figure 1. When you poke the head, the spring is moved out of its resting position. It then bounces back and forth with two degrees of freedom: a radial component R and an angular component Theta.
The position for a linear spring's motion is given by the equation:
x = A Cos(2 Π F T)
Here:
 A is the amplitude (basically the spring's initial displacement)
 F is a constant that represents how floppy the spring is
 T is time
Over time, the equation makes x oscillate between A and +A.
This example uses the equation twice to model R and Theta as they change over time. The program uses the following variables in the equations.
private float Ar, Aa, Fr, Fa;
private float T = 0;
private const float Dampen = 0.95f;
Here Ar and Aa are the A terms in the radial (R) and angular (Theta) equations. The values Fr and Fa are the F terms in the equations. T tracks the time and Dampen is a factor used later to reduce the oscillations over time so the bobbling eventually stops.
When you click on the program's picture, the following code starts the head bobbling.
// Start bobbling.
private Random Rand = new Random();
private void picBobble_Click(object sender, EventArgs e)
{
Ar = Rand.Next(10, 20);
if (Rand.Next(0, 2) == 0) Ar = Ar;
Aa = Rand.Next(10, 20);
if (Rand.Next(0, 2) == 0) Aa = Aa;
Fr = Rand.Next(7, 15) / 10f;
Fa = Rand.Next(7, 15) / 10f;
T = 0;
tmrBobble.Enabled = true;
}
This code simply picks random values for Ar, Aa, Fr, and Fa. It then sets T = 0 and enables the timer tmrBobble. The following code shows the timer's Tick event handler.
// A*Cos(2*pi*f*t)
private void tmrBobble_Tick(object sender, EventArgs e)
{
float r = (float)(Ar * Math.Cos(2 * Math.PI * Fr * T));
float theta = (float)(Aa * Math.Cos(2 * Math.PI * Fa * T));
DrawHead(r, theta);
T += 0.1f;
Ar *= Dampen;
Aa *= Dampen;
if ((Math.Abs(Ar) < 0.1) && (Math.Abs(Aa) < 0.1f))
tmrBobble.Enabled = false;
}
This event handler uses the equation to calculate new values for r and theta, and calls the DrawHead method described shortly. It then adds 0.1 to T and multiplies Ar and Aa by Dampen to make them smaller. When they get small enough, the code disables the timer so the bobbling stops.
The following code shows the DrawHead method.
// Draw the head at the indicated position.
private void DrawHead(float r, float theta)
{
BmCombined = (Bitmap)BmBody.Clone();
using (Graphics gr = Graphics.FromImage(BmCombined))
{
gr.TranslateTransform(Chin.X, Chin.Y, MatrixOrder.Append);
gr.RotateTransform(theta, MatrixOrder.Append);
gr.TranslateTransform(0, r, MatrixOrder.Append);
gr.TranslateTransform(Chin.X, Chin.Y, MatrixOrder.Append);
gr.DrawImage(BmHead, Origin);
}
picBobble.Image = BmCombined;
picBobble.Refresh();
}
This method makes a new combined image by copying the body image. It then creates a Graphics object to work with the image and adds transformations so the head will be transformed when the program draws it on the image.
The first transformation translates the head so its chin is at (0, 0). It then rotates the head by theta degrees and translates it by the distance r vertically. Finally it translates the head so its chin position is back where it started. The result is that the head looks like it is undergoing the oscillations described by the equations with a spring attached at the chin's position.
After setting up the transformations, the code draws the head and displays the result.
Feel free to experiment with the program's parameters. Try changing the method the program uses to pick random equation parameters. Or try setting Dampen to 1.0 or 1.01 to see what happens.
And of course make new versions that use other politicians' images.
Download the example to experiment with it and to see additional details.
