Clawish
Clawish

Reputation: 2964

Draw centered in form on moving image

I'm trying to implement a small tool that draws sin and cos functions. The program is supposed to draw from the center of the form, so that the history will extend to the right. Imagine the following gif but with the right end of the line moving up and down, and the path to the left "showing the trace"

enter image description here

What I would like to do is, every time a timer elapses, draw a point (via Graphics.FillRectangle) in the center of a PictureBox. In the next timer fire move the graphics one pixel to the left, and draw the next pixel. This is what I have so far:

Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
  bmp = New Drawing.Bitmap(PictureBox1.Size.Width, PictureBox1.Size.Height)
  g1 = Graphics.FromImage(bmp)

  MathTimer = New Timers.Timer(30)
  AddHandler MathTimer.Elapsed, AddressOf OnTimedEvent
  MathTimer.Enabled = True
  MathTimer.Start()
End Sub

Private Sub OnTimedEvent(source As Object, e As System.Timers.ElapsedEventArgs)
  g1.FillRectangle(Brushes.Red, PictureBox1.Size.Width \ 2, PictureBox1.Size.Height \ 2, 1, 1)
  g1.TranslateTransform(-1, 0)
  PictureBox1.Image = bmp
End Sub

However, this doesn't achieve the desired effect, since the canvas of the graphics object g1 is moved to the left with this. Eventually it's not drawing anymore. (No wonder, since with this I'm drawing "with the left end of the line")

Anybody have a better idea that achieves the desired effect?

Upvotes: 0

Views: 130

Answers (1)

jAC
jAC

Reputation: 5324

For i As Integer = 0 To pointsToDraw.Count - 2
    Dim p As Point = pointsToDraw(i)
    Dim xPos As Integer = (pctrBxSinCosDraw.Width / 2) + p.X - currentTick
    e.Graphics.FillRectangle(Brushes.Black, xPos, CInt(p.Y + pctrBxSinCosDraw.Height / 2), 1, 1)
    If xPos <= 0 Then
        pointsToDraw.RemoveAt(i)
    End If
Next

Where currentTick is set by a Timer, which on Tick, calculates the x/y values:

Dim yVal As Double
If useSinCalc Then
    yVal = Math.Sin(DegreeToRadian(currentTick)) * (180 / Math.PI)
Else
    yVal = Math.Cos(DegreeToRadian(currentTick)) * (180 / Math.PI)
End If
pointsToDraw.Add(New Point(currentTick, yVal))
currentTick += 1
pctrBxSinCosDraw.Invalidate()

And DegreeToRadian simply does (as it states):

Private Function DegreeToRadian(ByVal angle As Double)
    DegreeToRadian = Math.PI * angle / 180.0
End Function

And pointsToDraw is List(Of Point)

A sample project can be found on my download page.

Upvotes: 1

Related Questions