C# and F# – Imaginary number Kata

Imaginary Numbers Kata:

I didn’t fully get imaginary numbers and I needed a bit of fundamental C# practice, so today’s few minutes kata is to use some code to understand imaginary numbers. Please look to Khalid at <www.betterexplained.com> to really understand them! Give numbers a dimension to rotate in.

Specification: put in some imaginary numbers, draw the resulting triangle and test my understanding of what the magnitude really is. A quickly and basically as possible. Twenty minutes to write it, a bit longer to fix some misconceptions about drawing in Winforms.

I’ve elided the rest of the surrounding form bits.

using System.Numerics;
public partial class Form1 : Form
{
    private Graphics g;
    public Form1()
    {
        InitializeComponent();
    }

    private void pictureBox1_Paint(object sender, PaintEventArgs e)
    {
        g = this.CreateGraphics();
        DrawTriangle(realPart, imaginaryPart);
    }

    private void DrawTriangle(float rPart, float iPart)
    { 
        DrawTriangle(rPart, iPart,  new System.Drawing.Pen(System.Drawing.Color.Red));
    }
    private float realPart = 20;
    private float imaginaryPart = 50;

    private void DrawTriangle(float rPart, float iPart, Pen myPen)
    {
        //2,5
        g.Clear(Form1.DefaultBackColor);
        Complex c1 = new Complex(rPart, iPart);

        PointF Center = CenterForm();

        float xOffset = Center.X;
        float yOffset = Center.Y;
        rPart += xOffset;
        iPart += yOffset;

        g.DrawLine(myPen, new PointF(rPart, yOffset), Center);

        g.DrawLine(myPen, new PointF(xOffset, iPart), Center);
        g.DrawLine(myPen, new PointF(rPart, yOffset), new PointF(xOffset, iPart));
        labelC.Text = String.Format("Real: {0}\nImaginary: {1}\nHyp:{2}\nMagnitude:{3}\n ",
           c1.Real,
           c1.Imaginary,
           Math.Sqrt(Math.Pow(c1.Real, 2) + Math.Pow(c1.Imaginary, 2)),
           c1.Magnitude); 
    }

    private PointF CenterForm()
    {
        int x = this.Size.Height / 2;
        int y = this.Size.Width / 2;
        return new PointF(x, y);
    }

    private void Form1_Load(object sender, EventArgs e)
    {
    }

    private void Form1_SizeChanged(object sender, EventArgs e)
    {
        DrawTriangle(realPart, imaginaryPart);
    }

    private void textBox1_TextChanged(object sender, EventArgs e)
    {
        float temp;
        float.TryParse(realPartInput.Text, out temp);
        if (float.TryParse(realPartInput.Text, out temp)) realPart = temp;
        DrawTriangle(realPart, imaginaryPart);
    }

    private void textBox2_TextChanged(object sender, EventArgs e)
    {
        float temp;
        float.TryParse(imaginaryPartInput.Text, out temp);
        if (float.TryParse(imaginaryPartInput.Text, out temp)) imaginaryPart = temp;
        DrawTriangle(realPart, imaginaryPart);
    }


}

imagine

Before you say it, the F# version requires all Forms code to be done up front, not in a designer so this primitive version is not factored at all and has my first stab at some graph lines in it. Notice the manual addition of events too.

open System.Drawing
open System.Numerics
open Microsoft.FSharp.Math
open System.Windows.Forms

let form1 = new Form(Text = "Imaginary Numbers", Visible = true)


let redPen = new System.Drawing.Pen(System.Drawing.Color.Red) 
let greyPen = new System.Drawing.Pen(System.Drawing.Color.DarkSlateGray)

let labelC = new Label(Location = new Point(10,30), Height = 100, Width = 200, Visible = true) 

type hLine = {Left: float32; Right:float32}
type vLine = {Top: float32; Bottom:float32}
let DrawTriangle (rPart:float32, iPart: float32) = 
                                  let g = form1.CreateGraphics()
                                  let center =    
                                            let x = float32 (form1.Size.Width / 2)
                                            let y = float32 (form1.Size.Height / 2)
                                            new PointF(x, y)
                                  let lineX = { Left = float32 (40); Right = float32 (form1.Size.Width - 80)}


                                  let lineY ={Top = float32 ( 40) ;Bottom = float32 (form1.Size.Height  - 80)}

                                  let c1 = new Complex(float rPart, float iPart)
                                  g.Clear(form1.BackColor) 
                                  let xOffset = center.X
                                  let yOffset = center.Y
                                  let rPart = rPart + xOffset
                                  let iPart = iPart + yOffset
                                  g.DrawLine(greyPen, new PointF(lineX.Left,center.X), new PointF(lineX.Right,center.X))
                                  g.DrawLine(greyPen, new PointF(center.Y,lineY.Top), new PointF(center.Y, lineY.Bottom))
                                  g.DrawLine(redPen, new PointF(rPart, yOffset), center) 
                                  g.DrawLine(redPen, new PointF(xOffset, iPart), center) 
                                  g.DrawLine(redPen, new PointF(rPart, yOffset), new PointF(xOffset, iPart)) 

                                  let lbl = System.String.Format("Real: {0}\nImaginary: {1}\nHyp:{2}\nMagnitude:{3}\n ",
                                                                      c1.Real,
                                                                      c1.Imaginary,
                                                                      sqrt(pown c1.Real  2  + pown c1.Imaginary  2 ),
                                                                      c1.Magnitude) 
                                  labelC.Text <- lbl



do form1.Controls.Add(labelC) 

let rPartBox = new TextBox(Location = new Point(10, 10))
let iPartBox = new TextBox(Location = new Point(150, 10))

for c in [rPartBox; iPartBox] do form1.Controls.Add(c) 


let getParts = fun evargs -> match rPartBox.Text.Length, 
                                   iPartBox.Text.Length with | (0,0) -> DrawTriangle (20.F, 50.F) 
                                                             | _ -> DrawTriangle (float32( snd (System.Double.TryParse rPartBox.Text)),
                                                                                  float32(snd (System.Double.TryParse iPartBox.Text)))

iPartBox.TextChanged.Add(getParts)
form1.SizeChanged.Add(getParts)

Application.Run()