Results 1 to 19 of 19

Thread: Fast update of bitmap from polar coordinate data

Threaded View

  1. #18
    PowerPoster boops boops's Avatar
    Join Date
    Nov 2008
    Location
    Holland/France
    Posts
    3,201

    Re: Fast update of bitmap from polar coordinate data

    Hi chriscross,

    Unfortunately I was mistaken about the XNA example. I found the demo that Jenner made (it was from this thread, post#10) but unfortunately the link is now dead. I dug out the code but I think it will take a lot of work to convert it to something you can use; there is too much I don't know about XNA.

    Still, I made my own attempt at a "radar" screen which you might find interesting for comparison. With an angular resolution of 1 degree it takes me about 3-4 seconds to do a full 360 degree sweep. It uses random data for each echo line.

    It seems that most of the time goes into updating the bitmap with the new line (not the rendering after all). I almost doubled the performance up by drawing 2 lines in each pass, and the speed could be further improved by increasing that to 3 or more.

    I widened the line bitmap to 3 pixels to provide a kind of anti-aliasing. (The middle line has the data at full opacity, and the first and third lines the same data partly transparent). It seems this costs little extra time and the resulting scan is much smoother.

    If you want to try it you can just copy the code below into a default form. There's no need to do anything in the designer. You can resize the form to enlarge the scan. The timing results are shown in the Output window.

    Code:
    Public Class Form1
    
    	Private WithEvents tim As New Timer With {.Interval = 15}
    	Private WithEvents pictureBox1 As New PictureBox
    	Private sw As Stopwatch
    
    	Private echo1() As Integer 'echo data array 1
    	Private echo2() As Integer 'echo data array 2
    	Private echoResolution As Integer	'was "scale"
    	Private angleResolution As Single = 1
    	Private rnd As New Random
    	Private scanBitmap As Bitmap 'was "bm"
    	Private echoLine1 As Bitmap
    	Private echoLine2 As Bitmap
    	Private angle As Single
    
    	Private refreshInterval As Integer = 1
    	Private fadeInterval As Integer = 4
    	Private refreshCount As Integer
    	Private fadeCount As Integer
    
    	'setup in the load event:
    	Private Sub Form1_Load(sender As System.Object, e As System.EventArgs) Handles MyBase.Load
    		Me.ClientSize = New Size(600, 600)
    		PictureBox1.BackColor = Color.FromArgb(0, 50, 20)
    		pictureBox1.Dock = DockStyle.Fill
    		Me.Controls.Add(pictureBox1)
    		tim.Start()
    	End Sub
    
    	'some setup in the SizeChanged event, to allow user resizing
    	Private Sub PictureBox1_SizeChanged(sender As Object, e As System.EventArgs) Handles pictureBox1.SizeChanged
    		scanBitmap = New Bitmap(pictureBox1.Width, pictureBox1.Height)
    		echoResolution = pictureBox1.Width \ 2 - 5
    		ReDim echo1(echoResolution - 1)
    		ReDim echo2(echoResolution - 1)
    		echoLine1 = New Bitmap(echoResolution, 3)
    		echoLine2 = New Bitmap(echoResolution, 3)
    	End Sub
    
    	Private Sub PictureBox1_Paint(sender As Object, e As System.Windows.Forms.PaintEventArgs) Handles pictureBox1.Paint
    
    		'draw a sweep indicator line
    		e.Graphics.SmoothingMode = Drawing2D.SmoothingMode.AntiAlias
    		Dim centre As New Point(pictureBox1.Width \ 2, pictureBox1.Height \ 2)
    		Using mtx As New Drawing2D.Matrix
    			mtx.RotateAt(angle + 0.2F, centre)
    			e.Graphics.Transform = mtx
    			Using pn As New Pen(Color.LightGreen, 1)
    				e.Graphics.DrawLine(pn, centre, New Point(pictureBox1.Width - 5, centre.Y))
    			End Using
    		End Using
    
    	End Sub
    
    	Private Sub Timer1_Tick(sender As Object, e As System.EventArgs) Handles tim.Tick
    		'update the bitmap and depending on the refreshinterval, put it in the picture box
    		UpdateScanBitmap()
    		refreshCount = (refreshCount + 1) Mod refreshInterval
    		If refreshCount = 0 Then pictureBox1.Image = scanBitmap
    		fadeCount = (fadeCount + 1) Mod fadeInterval
    		If fadeCount = 0 Then scanBitmap = FadeImage(scanBitmap, 98)
    	End Sub
    
    	'Update the scan:
    	Private Sub UpdateScanBitmap()
    		If sw Is Nothing Then sw = Stopwatch.StartNew
    
    		'create a set of simulated data for the echo line:
    		For d As Integer = 0 To echo1.Count - 1
    			echo1(d) = rnd.Next(0, 255)
    			echo2(d) = rnd.Next(0, 255)
    		Next
    
    		'conver the data to a line bitmap:
    		echoLine1 = GetEchoBitmap(echo1, echoLine1)
    		echoLine2 = GetEchoBitmap(echo2, echoLine2)
    
    		'draw the echo lines on the scan
    		Using g As Graphics = Graphics.FromImage(scanBitmap)
    			Dim centre As New Point(pictureBox1.Width \ 2, pictureBox1.Height \ 2)
    			Using mtx As New Drawing2D.Matrix
    				mtx.RotateAt(angle, centre)	'
    				g.Transform = mtx 'rotate the Graphics
    				g.DrawImageUnscaled(echoLine1, centre.X, centre.Y - 1)
    				mtx.RotateAt(angleResolution, centre)
    				g.Transform = mtx
    				g.DrawImageUnscaled(echoLine2, centre.X, centre.Y - 1)
    			End Using
    		End Using
    
    		'update the angle 
    		angle = (angle + 2 * angleResolution) Mod 360.0F
    
    		'provide feedback in the Output window:
    		If angle < angleResolution Then
    			angle = angle Mod 360.0F
    			Console.WriteLine("360 deg. sweep time = " & ((sw.ElapsedMilliseconds / 1000).ToString("N4")))
    			sw = Stopwatch.StartNew
    		End If
    
    	End Sub
    
    	Private Function GetEchoBitmap(echo As Integer(), echoLine As Bitmap) As Bitmap
    		Using fp As New FastPix(echoLine)
    			Dim pixels() As Integer = fp.PixelArray
    			For radius As Integer = 0 To echoResolution - 1
    				Dim data As Integer = echo(radius) * 256
    				pixels(radius) = &HAF000000 + data
    				pixels(radius + echoResolution) = &HFF000000 + data
    				pixels(radius + 2 * echoResolution) = &HAF000000 + data
    			Next
    		End Using
    		Return echoLine
    	End Function
    
    	Private Function FadeImage(bmp As Bitmap, opacityPercent As Double) As Bitmap
    		'set the opacity of an image:
    		If opacityPercent >= 0 AndAlso opacityPercent <= 100 Then
    			Dim alphaRatio = opacityPercent / 100
    			Using fp As New FastPix(bmp)
    				Dim pixels() = fp.PixelArray
    				For i As Integer = 0 To pixels.Count - 1
    					Dim pixel = pixels(i)
    					Dim alpha As Integer = (pixel >> 24) And &HFF
    					alpha = CInt(alphaRatio * alpha) << 24
    					pixels(i) = pixel And &HFFFFFF Or alpha
    				Next
    			End Using
    			Return bmp
    		Else
    			Console.WriteLine("FadeImage: opacityPercent must be in the range 0-100.")
    			Return Nothing
    		End If
    	End Function
    
    End Class
    BB

Posting Permissions

  • You may not post new threads
  • You may not post replies
  • You may not post attachments
  • You may not edit your posts
  •  



Click Here to Expand Forum to Full Width