Public Class Form1

  Dim Background As New Bitmap(600, 400)
  Dim running As Boolean = True

  Dim mode As String
  Dim period As Double = 10
  Dim eccentricity As Double
  Dim Kx, Ky As Double
  Dim Bx, By As Double
  Dim Dx, Dy As Double
  Dim Ex1, Ey1 As Double
  Dim Px, Py As Double
  Dim ox, oy As Integer

  Dim EccentricAnomaly As Double
  Dim TrueAnomaly As Double

  Dim deferent1, deferent2 As Integer ' deferent 1 is the radius of the elliptical orbit, deferent 2 is radius of the circular orbit
  ' In the case of the Moon, deferent 2 = 0
  ' In the case of Venus, deferent 1 is the solar deferent, deferent2 is the planetary deferent.
  ' In the case of Mars, deferent 1 is  the planetary deferent, deferent2 is the solar deferent.
  ' The reason for this is that all Ptolemy's epicycles were circular. Only the main deferent was eccentric.
  ' In the case of the inferior planets, this was the solar deferent
  ' In the case of the superior planets, this was the planetary deferent.

  Dim theta1, theta2 As Double ' theta 1 is angle of the solar deferen, theta2 is angle of planetary deferent
  Dim ratio As Double ' ratio is period of planet in years
  Dim offsetfraction, offset As Double
  Dim Equant As Boolean
  Dim epicycle1 As Double
  Dim antiphase1 As Integer
  Dim frequency1 As Integer
  Dim dashedpen As New Pen(Color.Red, 1)

  Dim AngDisc, AngDiscMax, AngDiscMin As Double
  Dim RadDisc, RadDiscMax, RadDiscMin As Double

  'planetary periods
  Dim Pmoon As Double = 0.08
  Dim Pvenus As Double = 0.615
  Dim Psun As Double = 1
  Dim Pmars As Double = 1.9

  'planetary ratio of epicycle to deferent
  Dim Rvenus As Double = 0.72
  Dim Rmars As Double = 1.5

  'size of deferent
  Dim Dmoon As Integer = 6
  Dim Dvenus As Integer = 24
  Dim Dsun As Integer = 44
  Dim Dmars As Integer = 100
  Dim Douter As Integer = 260

  Dim time As Integer = 0

  Private Sub Form1_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
    dashedpen.DashStyle = Drawing2D.DashStyle.Dash
    RadioButton1.Checked = True ' this sets the mode
    CheckBox7.Checked = False : Equant = False
    antiphase1 = 1
    frequency1 = 0
    PictureBox1.BackgroundImage = Background
    Timer1.Interval = 50
    Timer1.Start()
  End Sub

  Private Sub PictureBox1_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
    Dim r, s As Integer
    e.Graphics.TranslateTransform(300, 200)
    e.Graphics.ScaleTransform(1, -1)
    Select Case mode
      Case "Moon"
        ' Bx and By are both zero so can be ignored
        r = 10 : s = 4
        FillCircle(e.Graphics, Brushes.Aqua, 0, 0, 20) ' Earth
        DrawCircle(e.Graphics, Pens.Blue, -offset, 0, deferent1) ' deferent
        If Equant Then
          e.Graphics.DrawLine(Pens.Violet, CInt(-2 * offset), 0, CInt(Dx + Ex1 - offset), CInt(Dy + Ey1))
          FillCircle(e.Graphics, Brushes.Violet, -2 * offset, 0, 4) ' centre of equant
        End If
        DrawCircle(e.Graphics, Pens.Blue, Dx - offset, Dy, epicycle1) ' epicycle 1
        FillCircle(e.Graphics, Brushes.White, Kx, Ky, r) ' real Moon
        DrawCircle(e.Graphics, Pens.LightGray, Px, Py, r) ' simulated Moon
        ox = 0 : oy = 0
        DrawLine(e.Graphics, dashedpen, -offset, 0)
        DrawLine(e.Graphics, Pens.Red, Dx - offset, Dy)
        DrawLine(e.Graphics, Pens.Red, Dx + Ex1 - offset, Dy + Ey1)
      Case "Mars"
        r = 4 : s = 6
        ox = 0 : oy = 0
        FillCircle(e.Graphics, Brushes.Aqua, 0, 0, r) ' Earth
        If CheckBox2.Checked Then
          DrawCircle(e.Graphics, Pens.Blue, 0, 0, deferent2) ' solar deferent
          DrawCircle(e.Graphics, Pens.Blue, Bx - offset, By, deferent1) ' planetary deferent
          If Equant Then
            e.Graphics.DrawLine(Pens.Violet, CInt(Bx - 2 * offset), CInt(By), CInt(Bx + Dx + Ex1 - offset), CInt(By + Dy + Ey1))
            FillCircle(e.Graphics, Brushes.Violet, Bx - 2 * offset, By, 4) ' centre of equant
          End If
          DrawLine(e.Graphics, Pens.Red, Bx, By)
          DrawLine(e.Graphics, dashedpen, Bx - offset, By)
        Else
          DrawCircle(e.Graphics, Pens.Blue, -offset, 0, deferent1) ' planetary deferent
          DrawCircle(e.Graphics, Pens.Blue, Dx - offset, Dy, deferent2) ' solar deferent
          If Equant Then
            e.Graphics.DrawLine(Pens.Violet, CInt(-2 * offset), 0, CInt(Dx + Ex1 - offset), CInt(Dy + Ey1))
            FillCircle(e.Graphics, Brushes.Violet, -2 * offset, 0, 4) ' centre of equant
          End If
          DrawLine(e.Graphics, dashedpen, -offset, 0)
          DrawLine(e.Graphics, Pens.Red, Dx - offset, Dy)
        End If
        DrawLine(e.Graphics, Pens.Red, Bx + Dx - offset, By + Dy)
        DrawLine(e.Graphics, Pens.Red, Bx + Dx + Ex1 - offset, By + Dy + Ey1)
        DrawLine(e.Graphics, Pens.Red, Px, Py)
        DrawCircle(e.Graphics, Pens.Blue, Bx + Dx - offset, By + Dy, epicycle1) ' epicycle 1
        FillCircle(e.Graphics, Brushes.Orange, Kx, Ky, r) ' real Mars
        DrawCircle(e.Graphics, Pens.Orange, Px, Py, r) ' simulated Mars
        FillCircle(e.Graphics, Brushes.Yellow, Bx / 2.6, By / 2.6, s) ' position of sun
      Case "Venus"
        r = 4 : s = 10
        ox = 0 : oy = 0
        FillCircle(e.Graphics, Brushes.Aqua, 0, 0, r) ' Earth
        DrawCircle(e.Graphics, Pens.Blue, -offset, 0, deferent1) 'solar deferent
        DrawCircle(e.Graphics, Pens.Blue, Dx - offset, Dy, deferent2) '  planetary deferent
        If Equant Then
          e.Graphics.DrawLine(Pens.Violet, CInt(-2 * offset), 0, CInt(Dx + Ex1 - offset), CInt(Dy + Ey1))
          FillCircle(e.Graphics, Brushes.Violet, -2 * offset, 0, 4) ' centre of equant
        End If

        DrawLine(e.Graphics, dashedpen, -offset, 0)
        DrawLine(e.Graphics, Pens.Red, Dx - offset, Dy)
        DrawLine(e.Graphics, Pens.Red, Bx + Dx - offset, By + Dy)
        DrawLine(e.Graphics, Pens.Red, Bx + Dx + Ex1 - offset, By + Dy + Ey1)
        DrawLine(e.Graphics, Pens.Red, Px, Py)

        DrawCircle(e.Graphics, Pens.Blue, Bx + Dx - offset, By + Dy, epicycle1) ' epicycle 1
        FillCircle(e.Graphics, Brushes.White, Kx, Ky, r) ' real Venus
        DrawCircle(e.Graphics, Pens.White, Px, Py, r) ' simulated venus
        FillCircle(e.Graphics, Brushes.Yellow, 2 * Dx - offset, 2 * Dy, s) '  position of sun
    End Select
    If CheckBox1.Checked Then
      Plot(Kx + 300, -Ky + 200)
      Plot(Px + 300, -Py + 200)
    End If
  End Sub

  Private Sub PictureBox2_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox2.Paint
    Dim r As Integer
    With e.Graphics
      .TranslateTransform(300, 60)
      For i As Integer = -200 To 200 Step 40
        .DrawLine(Pens.LightGray, i, -50, i, 50)
      Next
      .DrawString("LEAD", New Font("Ariel", 12), Brushes.White, -290, -40)
      .DrawString("LAG", New Font("Ariel", 12), Brushes.White, 246, -40)
      Select Case mode
        Case "Moon"
          r = 10
          .FillEllipse(Brushes.White, -r, -r, 2 * r, 2 * r)
          .DrawEllipse(Pens.LightGray, CInt(7200 / Math.PI * AngDisc - r), -r, 2 * r, 2 * r)
        Case "Mars"
          r = 5
          .FillEllipse(Brushes.Orange, -r, -r, 2 * r, 2 * r)
          .DrawEllipse(Pens.Orange, CInt(7200 / Math.PI * AngDisc - r), -r, 2 * r, 2 * r)
        Case "Venus"
          r = 5
          .FillEllipse(Brushes.White, -r, -r, 2 * r, 2 * r)
          .DrawEllipse(Pens.White, CInt(7200 / Math.PI * AngDisc - r), -r, 2 * r, 2 * r)
      End Select
    End With
  End Sub

  Private Sub PictureBox3_Paint(ByVal sender As Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox3.Paint
    Dim r, s As Integer
    e.Graphics.TranslateTransform(300, 274)
    e.Graphics.ScaleTransform(1, -1)
    FillCircle(e.Graphics, New SolidBrush(Color.FromArgb(&HFF405040)), 0, 0, Douter)
    FillCircle(e.Graphics, New SolidBrush(Color.FromArgb(&HFF506050)), 0, 0, Dsun)
    FillCircle(e.Graphics, New SolidBrush(Color.FromArgb(&HFF708070)), 0, 0, Dmoon)
    Dim x, y As Double
    r = 2 : s = 4
    x = Dmars * (Math.Cos(theta1) + Rmars * Math.Cos(theta1 / Pmars))
    y = Dmars * (Math.Sin(theta1) + Rmars * Math.Sin(theta1 / Pmars))
    FillCircle(e.Graphics, New SolidBrush(Color.FromArgb(&HFF586858)), Dmars * Rmars * Math.Cos(theta1 / Pmars), Dmars * Rmars * Math.Sin(theta1 / Pmars), Dmars)
    FillCircle(e.Graphics, Brushes.Orange, x, y, r) 'Mars
    x = Dsun * Math.Cos(theta1)
    y = Dsun * Math.Sin(theta1)
    FillCircle(e.Graphics, Brushes.Yellow, x, y, s) 'Sun
    x = Dvenus * (Math.Cos(theta1) + Rvenus * Math.Cos(theta1 / Pvenus))
    y = Dvenus * (Math.Sin(theta1) + Rvenus * Math.Sin(theta1 / Pvenus))
    FillCircle(e.Graphics, New SolidBrush(Color.FromArgb(&HFF687868)), Dvenus * Math.Cos(theta1), Dvenus * Math.Sin(theta1), Dvenus * Rvenus)
    FillCircle(e.Graphics, Brushes.White, x, y, r) 'Venus
    x = Dmoon * Math.Cos(theta1 / Pmoon)
    y = Dmoon * Math.Sin(theta1 / Pmoon)
    FillCircle(e.Graphics, Brushes.White, x, y, r) 'Moon
    FillCircle(e.Graphics, Brushes.Aqua, 0, 0, s) ' Earth
  End Sub

  Private Sub Timer1_Tick(ByVal sender As Object, ByVal e As System.EventArgs) Handles Timer1.Tick
    time += 1
    ReCalculate()
  End Sub
  Private Sub ReCalculate()
    Select Case mode
      Case "The lot"
        theta1 = 2 * Math.PI * time * Timer1.Interval / (1000 * period)
        Label7.Text = "" : Label8.Text = "" : Label9.Text = ""
        Label10.Text = "" : Label11.Text = "" : Label12.Text = ""
      Case Else
        offsetfraction = NumericUpDown3.Value / 100
        offset = offsetfraction * deferent1
        Label2.Text = "Offset fraction =" & Str(NumericUpDown3.Value) & " %"
        epicycle1 = NumericUpDown4.Value * deferent1 / 100
        Label3.Text = "Epicycle radius =" & Str(NumericUpDown4.Value) & " %"
        theta1 = 2 * Math.PI * time * Timer1.Interval / (1000 * period)
        theta2 = theta1 / ratio
        ' calculate real orbit (Kx, Ky)
        EccentricAnomaly = Kepler(theta1)
        Dim x As Double = Math.Sqrt(1 - eccentricity) * Math.Cos(EccentricAnomaly / 2)
        Dim y As Double = Math.Sqrt(1 + eccentricity) * Math.Sin(EccentricAnomaly / 2)
        TrueAnomaly = 2 * ArcTangent(y, x)
        If TrueAnomaly > Math.PI Then TrueAnomaly -= 2 * Math.PI
        If TrueAnomaly < -Math.PI Then TrueAnomaly += 2 * Math.PI
        Dim radius As Double = deferent1 * (1 - eccentricity ^ 2) / (1 + eccentricity * Math.Cos(TrueAnomaly))
        ' add in the second deferent (Bx, By)
        Bx = -deferent2 * Math.Cos(theta2) : By = -deferent2 * Math.Sin(theta2)
        Kx = radius * Math.Cos(TrueAnomaly) + Bx
        Ky = radius * Math.Sin(TrueAnomaly) + By
        ' calculate simulated orbit
        If Equant Then
          Dim m As Double = offsetfraction * Math.Cos(theta1)
          Dim d As Double = m + Math.Sqrt(m * m + 1 - offsetfraction * offsetfraction)
          Dx = deferent1 * (d * Math.Cos(theta1) - offsetfraction)
          Dy = deferent1 * d * Math.Sin(theta1)
        Else
          Dx = deferent1 * Math.Cos(theta1)
          Dy = deferent1 * Math.Sin(theta1)
        End If
        Ex1 = antiphase1 * epicycle1 * Math.Cos(frequency1 * theta1)
        Ey1 = antiphase1 * epicycle1 * Math.Sin(frequency1 * theta1)
        Px = Bx + Dx + Ex1 - offset : Py = By + Dy + Ey1
        ' calculate discrepancies
        AngDisc = ArcTangent(Ky, Kx) - ArcTangent(Py, Px)
        RadDisc = Math.Sqrt(Py * Py + Px * Px) - Math.Sqrt(Ky * Ky + Kx * Kx)
        If AngDisc > AngDiscMax Then AngDiscMax = AngDisc
        If AngDisc < AngDiscMin Then AngDiscMin = AngDisc
        If RadDisc > RadDiscMax Then RadDiscMax = RadDisc
        If RadDisc < RadDiscMin Then RadDiscMin = RadDisc
        Label7.Text = "Angular discrepancy = " & Format(180 * AngDisc / Math.PI, ".00")
        Label8.Text = "Max: " & Format(180 * AngDiscMax / Math.PI, ".00")
        Label9.Text = "Min: " & Format(180 * AngDiscMin / Math.PI, ".00") & " degrees"
        Label10.Text = "Radial discrepancy = " & Format(100 * RadDisc / deferent1, ".00")
        Label11.Text = "Max: " & Format(100 * RadDiscMax / deferent1, ".00")
        Label12.Text = "Min: " & Format(100 * RadDiscMin / deferent1, ".00") & " %"
    End Select
    If mode = "The lot" Then
      PictureBox3.Invalidate()
    Else
      PictureBox1.Invalidate() : PictureBox2.Invalidate()
    End If
  End Sub

  Private Sub ModeButtonsChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles RadioButton1.CheckedChanged, RadioButton2.CheckedChanged, RadioButton3.CheckedChanged, RadioButton4.CheckedChanged
    SetMode()
  End Sub
  Private Sub SetMode()
    Select Case True
      Case RadioButton1.Checked
        mode = "Moon"
        CheckBox2.Hide()
        GroupBox2.Show() : GroupBox3.Show() : CheckBox1.Show()
        PictureBox1.Show() : PictureBox2.Show() : PictureBox3.Hide()
        deferent1 = 160 : deferent2 = 0 : ratio = 1
        NumericUpDown6.Value = 5.5 : eccentricity = NumericUpDown6.Value / 100
        TrackBar2.Value = 0 : TrackBar3.Value = 0
        RichTextBox1.Text = "     The blue disc is the Earth, the white disc is real Moon while the grey circle is the simulated Moon. The eccentricity of the Moon's orbit is 5.5%"
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     In order to model an elliptical orbit, the deferent must be given a significant offset. Try a value equal to the eccentricity."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     Now click on the 'Equant' box and note the dramatic improvement."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     See if you can achieve the same result without using an Equant, using epicycles instead."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     (Epicycles with negative frequency rotate in the opposite direction. The size of the epicycle is expressed as a percentage of the deferent."
      Case RadioButton2.Checked
        mode = "Venus"
        CheckBox2.Hide()
        GroupBox2.Show() : GroupBox3.Show() : CheckBox1.Show()
        PictureBox1.Show() : PictureBox2.Show() : PictureBox3.Hide()
        deferent1 = 100 : deferent2 = 72 : ratio = Pvenus
        NumericUpDown6.Value = 1.6 : eccentricity = NumericUpDown6.Value / 100
        TrackBar2.Value = 0 : TrackBar3.Value = 0
        RichTextBox1.Text = "     The blue disc is the Earth, the white disc is the real Venus while the white circle is the simulated Venus."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     Venus takes 0.615 years to make one orbit from which it can be inferred that it overtakes Earth on the inside approximately every 19 months."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     These parameters have been built into the epicycle and deferent shown."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     Ptolemy assumed that Venus' orbit is perfectly circular. (It actually has an eccentricity of 0.7%)"
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     He compensated for the eccentricity of the Earth's orbit (which is 1.6%) by using an offset of 3.2%. Can you improve his fit by using either an equant or an epicycle?"
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     The Sun is shown orbiting outside the orbit of Venus because that is where Ptolemy put it. Clearly on this model, Venus would never show a complete set of phases because the Sun is always partially behind it."
      Case RadioButton3.Checked
        mode = "Mars"
        CheckBox2.Show()
        GroupBox2.Show() : GroupBox3.Show() : CheckBox1.Show()
        PictureBox1.Show() : PictureBox2.Show() : PictureBox3.Hide()
        deferent1 = 120 : deferent2 = 80 : ratio = 1 / Pmars ' this is because Ptolemy made the epicycle the solar deferent
        NumericUpDown6.Value = 9 : eccentricity = NumericUpDown6.Value / 100
        TrackBar2.Value = 0 : TrackBar3.Value = 0
        RichTextBox1.Text = "   The blue disc is the Earth, the orange disc is the real Mars while the orange circle is the simulated Mars."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "   Mars takes 1.9 years to make one orbit from which it can be inferred that it is at its closest to Earth every 2.1 years."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "   These parameters have been built into the epicycle and deferent shown."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "   Ptolemy effectively assumed that the Earth's orbit was perfectly circular. He compensated for the eccentricity of Mars' orbit (which is about 9%) by using a 9% offset and an equant. Can you do as well using an epicycle instead?"
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "  The Sun is shown orbiting inside the orbit of Mars because that is where Ptolemy put it. Notice how retrograde motions always occur when the planet is in opposition."
      Case RadioButton4.Checked
        mode = "The lot"
        CheckBox2.Hide()
        GroupBox2.Hide() : GroupBox3.Hide() : CheckBox1.Hide()
        PictureBox1.Hide() : PictureBox2.Hide() : PictureBox3.Show()
        RichTextBox1.Text = "     Ptolemy placed his planets in the following order out from Earth: Moon; Mercury; Venus; Sun; Mars; Jupiter; Saturn."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     In this model only the Moon, Venus, Sun and Mars are shown and for simplicity, all are assumed to have circular orbits. The relative periods and dimensions are, however, correct."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     Owing to the fact that Venus and Mars have such large planetary deferents, their shells are very thick. The Sun and Moon, having nearly circular orbits occupy very thin shells."
        RichTextBox1.Text += vbNewLine & vbNewLine
        RichTextBox1.Text += "     The planetary deferents of Venus and Mars are shown revolving within their crystal spheres."
    End Select
    If mode = "The lot" Then
      RichTextBox1.Location = New Point(627, 89)
      RichTextBox1.Size = New Size(320, 449)
    Else
      RichTextBox1.Location = New Point(627, 289)
      RichTextBox1.Size = New Size(320, 249)
    End If
    NumericUpDown3.Value = TrackBar2.Value
    NumericUpDown4.Value = TrackBar3.Value
    time = 0
  End Sub

  Private Sub ClearBackground()
    Dim g = Graphics.FromImage(Background)
    g.Clear(Color.Black)
  End Sub
  Private Sub StartStopButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button1.Click
    If running Then
      Timer1.Stop() : Button1.Text = "Start" : running = False
    Else
      Timer1.Start() : Button1.Text = "Pause" : running = True
    End If
  End Sub
  Private Sub Antiphase1_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox3.CheckedChanged
    If CheckBox3.Checked Then antiphase1 = -1 Else antiphase1 = 1
  End Sub
  Private Sub Equant_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox7.CheckedChanged
    Equant = CheckBox7.Checked
    AngDiscMax = 0 : AngDiscMin = 0 : RadDiscMax = 0 : RadDiscMin = 0
  End Sub
  Private Sub NumericUpDown1_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown1.ValueChanged
    frequency1 = NumericUpDown1.Value
    AngDiscMax = 0 : AngDiscMin = 0 : RadDiscMax = 0 : RadDiscMin = 0
  End Sub
  Private Sub NumericUpDown3_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown3.ValueChanged
    AngDiscMax = 0 : AngDiscMin = 0 : RadDiscMax = 0 : RadDiscMin = 0
    ReCalculate()
  End Sub
  Private Sub NumericUpDown4_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown4.ValueChanged
    AngDiscMax = 0 : AngDiscMin = 0 : RadDiscMax = 0 : RadDiscMin = 0
    ReCalculate()
  End Sub
  Private Sub NumericUpDown5_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs)
    AngDiscMax = 0 : AngDiscMin = 0 : RadDiscMax = 0 : RadDiscMin = 0
    ReCalculate()
  End Sub
  Private Sub NumericUpDown6_ValueChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles NumericUpDown6.ValueChanged
    'Timer1.Stop() : Button1.Text = "Start" : running = False
    eccentricity = NumericUpDown6.Value / 100
    Label1.Text = "Eccentricity =" & Str(NumericUpDown6.Value) & " %"
  End Sub
  Private Sub TrackBar2_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar2.Scroll
    NumericUpDown3.Value = TrackBar2.Value
  End Sub
  Private Sub TrackBar3_Scroll(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles TrackBar3.Scroll
    NumericUpDown4.Value = TrackBar3.Value
  End Sub
  Private Sub Trails_CheckedChanged(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles CheckBox1.CheckedChanged
    If CheckBox1.Checked = False Then ClearBackground()
  End Sub
  Private Sub ResetButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button2.Click
    time = 0
    AngDiscMax = 0 : AngDiscMin = 0 : RadDiscMax = 0 : RadDiscMin = 0
    ReCalculate()
  End Sub
  Private Sub HelpButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Button3.Click
    Dim f As String = My.Application.Info.DirectoryPath & "\Help.chm"
    Debug.Print(f)
    If IO.File.Exists(f) Then
      Process.Start(f)
    Else
      MsgBox("I cannot find a help file")
    End If
  End Sub

  Private Function Kepler(ByVal M)
    Dim E As Double = M
    Dim d As Double
    Dim n As Integer = 10
    Do
      d = (E - eccentricity * Math.Sin(E) - M) / (1 - eccentricity * Math.Cos(E))
      E = E - d
      n -= 1
    Loop Until Math.Abs(d) < 0.001 Or n = 0
    If n = 0 Then Beep() 'MsgBox("Newtons method failed.")
    Return E
  End Function
  Private Function ArcTangent(ByVal y, ByVal x)
    Select Case True
      Case y > 0 And x = 0 : Return Math.PI / 2
      Case y < 0 And x = 0 : Return -Math.PI / 2
      Case y > 0 And x > 0 : Return Math.Atan(y / x)
      Case y > 0 And x < 0 : Return Math.PI - Math.Atan(-y / x)
      Case y < 0 And x < 0 : Return -Math.PI + Math.Atan(y / x)
      Case y < 0 And x > 0 : Return -Math.Atan(-y / x)
    End Select
    Return 0
  End Function
  Private Sub DrawLine(ByVal g As Graphics, ByVal p As Pen, ByVal x As Integer, ByVal y As Integer)
    g.DrawLine(p, ox, oy, x, y)
    ox = x : oy = y
  End Sub
  Private Sub DrawCircle(ByVal g As Graphics, ByVal p As Pen, ByVal x As Integer, ByVal y As Integer, ByVal r As Integer)
    g.DrawEllipse(p, x - r, y - r, 2 * r, 2 * r)
  End Sub
  Private Sub FillCircle(ByVal g As Graphics, ByVal b As Brush, ByVal x As Integer, ByVal y As Integer, ByVal r As Integer)
    g.FillEllipse(b, x - r, y - r, 2 * r, 2 * r)
  End Sub
  Private Sub Plot(ByVal x As Integer, ByVal y As Integer)
    If x < 0 Or x >= 600 Or y < 0 Or y >= 400 Then Exit Sub
    Background.SetPixel(x, y, Color.White)
  End Sub
End Class
