Title: Draw a simple robot arm with a hand in C#
The example Draw a simple robot arm in C# shows how to use transformations to make it (relatively) easy to draw a robot arm. Each piece of the arm is transformed to account for the pieces closer to the arm's base, which is at the shoulder. See that example for the basic explanation.
This example adds a hand that opens and closes. The following code shows how the program draws its arm with the new code highlighted in blue.
// Draw the robot arm.
private void DrawRobotArm(Graphics gr)
{
const int UpperArmLength = 75;
const int LowerArmLength = 50;
const int WristLength = 20;
const int HandWidth = 48;
const int FingerLength = 30;
gr.SmoothingMode = SmoothingMode.AntiAlias;
gr.Clear(picCanvas.BackColor);
// For each stage in the arm, draw and then *prepend* the
// new transformation to represent the next arm in the sequence.
// Translate to center of form.
float cx = picCanvas.ClientSize.Width / 2;
float cy = picCanvas.ClientSize.Height / 2;
gr.TranslateTransform(cx, cy);
// **************
// Draw the arms.
GraphicsState initial_state = gr.Save();
// Make a rectangle to represent an arm.
// Later we'll set its width for each arm.
Rectangle rect = new Rectangle(0, -2, 100, 5);
// Rotate at the shoulder.
// (Negative to make the angle increase counter-clockwise).
gr.RotateTransform(-scrJoint1.Value, MatrixOrder.Prepend);
// Draw the first arm.
rect.Width = UpperArmLength;
gr.FillRectangle(Brushes.LightBlue, rect);
gr.DrawRectangle(Pens.Blue, rect);
// Translate to the end of the first arm.
gr.TranslateTransform(UpperArmLength, 0, MatrixOrder.Prepend);
// Rotate at the elbow.
gr.RotateTransform(-scrJoint2.Value, MatrixOrder.Prepend);
// Draw the second arm.
rect.Width = LowerArmLength;
gr.FillRectangle(Brushes.LightBlue, rect);
gr.DrawRectangle(Pens.Blue, rect);
// Translate to the end of the second arm.
gr.TranslateTransform(LowerArmLength, 0, MatrixOrder.Prepend);
// Rotate at the wrist.
gr.RotateTransform(-scrJoint3.Value, MatrixOrder.Prepend);
// Draw the third arm.
rect.Width = WristLength;
gr.FillRectangle(Brushes.LightBlue, rect);
gr.DrawRectangle(Pens.Blue, rect);
// ***********************************
// Draw the joints on top of the arms.
gr.Restore(initial_state);
// Draw the shoulder centered at the origin.
Rectangle joint_rect = new Rectangle(-4, -4, 9, 9);
gr.FillEllipse(Brushes.Red, joint_rect);
// Rotate at the shoulder.
// (Negative to make the angle increase counter-clockwise).
gr.RotateTransform(-scrJoint1.Value, MatrixOrder.Prepend);
// Translate to the end of the first arm.
gr.TranslateTransform(UpperArmLength, 0, MatrixOrder.Prepend);
// Draw the elbow.
gr.FillEllipse(Brushes.Red, joint_rect);
// Rotate at the elbow.
gr.RotateTransform(-scrJoint2.Value, MatrixOrder.Prepend);
// Translate to the end of the second arm.
gr.TranslateTransform(LowerArmLength, 0, MatrixOrder.Prepend);
// Draw the wrist.
gr.FillEllipse(Brushes.Red, joint_rect);
// **************
// Draw the hand.
// Rotate at the wrist.
gr.RotateTransform(-scrJoint3.Value, MatrixOrder.Prepend);
// Translate to the end of the wrist.
gr.TranslateTransform(WristLength, 0, MatrixOrder.Prepend);
// Draw the hand.
gr.FillRectangle(Brushes.LightGreen,
0, -HandWidth / 2, 4, HandWidth);
gr.DrawRectangle(Pens.Green,
0, -HandWidth / 2, 4, HandWidth);
gr.FillRectangle(Brushes.LightGreen,
4, -scrHand.Value - 4, FingerLength, 4);
gr.DrawRectangle(Pens.Green,
4, -scrHand.Value - 4, FingerLength, 4);
gr.FillRectangle(Brushes.LightGreen,
4, scrHand.Value, FingerLength, 4);
gr.DrawRectangle(Pens.Green,
4, scrHand.Value, FingerLength, 4);
}
There are only two main additions to this code beyond what was used in the previous example. First, the code moves to the end of the final wrist segment. It first rotates through the wrist's angle and then translates through the distance equal to the length of the wrist. That positions future drawing at the end of the arm where the hand should be.
The second change is merely the code that draws the hand.
Adding more segments to a robot arm is just as easy. Add a translation and rotation to move to the end of the current segment, and then draw the new section. The only real complication might occur if you want to draw certain parts of the arm (the joints in this example) on top of others. In that case, you may need to trace through the transformations more than once to draw each of the layers of pieces.
Download the example to experiment with it and to see additional details.
|