Introductory remarks
The purpose of this program is to rotate a mathematical plane around the x and z axes and to project this onto the 2D GUI.
First about the sign convention:
The plane lies in the xz-plane (so at the origin), where +x goes to the right, +y to the depth of the picture and +z to the top (compare: I look at another person as a person).
Many vectors are used to fill the surface. Depending on the size of the plane, there are often more than 40,000 vectors. So I decided to run the calculation function asynchronously. Since it is now cumbersome / nonsensical to paint in the PictureBox, I write in a bitmap, which I then assign to the PictureBox after each calculation process. Since the Graphics.DrawLine function reached its limits in terms of performance, I integrated SkiaSharp from Visual Studio's own Nuget package manager. Now, I write in an SKBtmap and can move the plane with the WASD keys and get a new image within a few hundred milliseconds.
For the projection, I use a formula that I found at StackOverflow a few months ago. I have now shown it clearly and distinctly. Since the plane partly comes towards me when turning, the distance to me changes. So, I subtract the distance_to_plane to get the real distance.
Dim projected As New PointF(
CSng((Camera - Window_distance) / (Camera - distance_to_plane) * rotatedVec.X),
CSng(-(Camera - Window_distance) / (Camera - distance_to_plane) * rotatedVec.Z))
What is my concern to you:
As you can see from the pictures, the plane has some curves (outliers) at the edges where it should be straight instead. I can't explain the effect.
I suspect the above formula. To remedy this, I set the camera very far away from the plane, and the projection window far away ‘enough’ from both the camera and the plane.
I'll put the complete source code online, maybe it's something else (a typical effect?).
Form ‘Create’ to instantiate a new plane.
Plane strongly rotated around the z-axis with odd edges in the middle. As you can see from the values, the camera is currently 2660 units of length away from the plane, and the projection window is 1000 units of length. (Camera – window 1660)
Form1.vb
Public NotInheritable Class FormMain
Private Plane1 As PlaneInTermsOfGeometry = Nothing
Public ReadOnly Deu As New System.Globalization.CultureInfo("de-DE")
Private Sub FormMain_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.BackColor = Color.FromArgb(184, 176, 143)
For Each but As Button In Me.Controls.OfType(Of Button)
but.BackColor = Color.FromArgb(201, 200, 193)
Next
TextBox_Window.Text = "-1000"
Label5.Text = ""
Label6.Text = ""
End Sub
Private Sub FormMain_Shown(sender As Object, e As EventArgs) Handles MyBase.Shown
New_Plane()
End Sub
Private Sub Button_new_plane_Click(sender As Object, e As EventArgs) Handles Button_new_plane.Click
New_Plane()
End Sub
Private Async Sub New_Plane()
Using FNP As New FormCreateNewPlane
If FNP.ShowDialog(Me) <> DialogResult.OK Then
Return
End If
Plane1 = New PlaneInTermsOfGeometry(
FNP.A0x,
FNP.A0y,
FNP.A0z,
FNP.ABx,
FNP.ABy,
FNP.ABz,
FNP.ACx,
FNP.ACy,
FNP.ACz,
FNP.Enlargement)
Await Plane1.process_async()
PictureBox1.Image = Nothing
PictureBox1.Image = PlaneInTermsOfGeometry.displayedBitmap
Label5.Text = Math.Round(Plane1.current_x_angle, 0).ToString(Deu)
Label6.Text = Math.Round(Plane1.current_z_angle, 0).ToString(Deu)
TextBox_Kamera.Text = Math.Round(Plane1.Camera, 0).ToString(Deu)
End Using
End Sub
Private Sub TextBox_Kamera_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Kamera.TextChanged
If Plane1 Is Nothing Then Return
Dim Kamera As Double
If Double.TryParse(TextBox_Kamera.Text, Kamera) Then
TextBox_Kamera.ForeColor = Color.FromArgb(0, 125, 0)
Plane1.Camera = Kamera
Else
TextBox_Kamera.ForeColor = Color.Red
End If
End Sub
Private Sub TextBox_Fenster_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Window.TextChanged
If Plane1 Is Nothing Then Return
Dim Fenster As Double
If Double.TryParse(TextBox_Window.Text, Fenster) Then
TextBox_Window.ForeColor = Color.FromArgb(0, 125, 0)
Plane1.Window_distance = Fenster
Else
TextBox_Window.ForeColor = Color.Red
End If
End Sub
Private Async Sub FormMain_KeyDown(sender As Object, e As KeyEventArgs) Handles MyBase.KeyDown
If Plane1 Is Nothing Then Return
Select Case e.KeyCode
Case Keys.W
If Plane1.current_x_angle > -90.0 Then
Plane1.change_x_angle(-1.0)
Await Plane1.process_async()
PictureBox1.Image = Nothing
GC.Collect()
PictureBox1.Image = PlaneInTermsOfGeometry.displayedBitmap
Label5.Text = Math.Round(Plane1.current_x_angle, 0).ToString(Deu)
Label6.Text = Math.Round(Plane1.current_z_angle, 0).ToString(Deu)
TextBox_KOForm.Text = Plane1.Cartesian_Equation()
End If
Case Keys.S
If Plane1.current_x_angle < 90.0 Then
Plane1.change_x_angle(1.0)
Await Plane1.process_async()
PictureBox1.Image = Nothing
GC.Collect()
PictureBox1.Image = PlaneInTermsOfGeometry.displayedBitmap
Label5.Text = Math.Round(Plane1.current_x_angle, 0).ToString(Deu)
Label6.Text = Math.Round(Plane1.current_z_angle, 0).ToString(Deu)
TextBox_KOForm.Text = Plane1.Cartesian_Equation()
End If
Case Keys.A
If Plane1.current_z_angle > -90.0 Then
Plane1.change_z_angle(-1.0)
Await Plane1.process_async()
PictureBox1.Image = Nothing
GC.Collect()
PictureBox1.Image = PlaneInTermsOfGeometry.displayedBitmap
Label5.Text = Math.Round(Plane1.current_x_angle, 0).ToString(Deu)
Label6.Text = Math.Round(Plane1.current_z_angle, 0).ToString(Deu)
TextBox_KOForm.Text = Plane1.Cartesian_Equation()
End If
Case Keys.D
If Plane1.current_z_angle < 90.0 Then
Plane1.change_z_angle(1.0)
Await Plane1.process_async()
PictureBox1.Image = Nothing
GC.Collect()
PictureBox1.Image = PlaneInTermsOfGeometry.displayedBitmap
Label5.Text = Math.Round(Plane1.current_x_angle, 0).ToString(Deu)
Label6.Text = Math.Round(Plane1.current_z_angle, 0).ToString(Deu)
TextBox_KOForm.Text = Plane1.Cartesian_Equation()
End If
Case Else
Exit Select
End Select
End Sub
Private Async Sub FormMain_MouseWheel(ByVal sender As Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles Me.MouseWheel
If Plane1 Is Nothing Then Return
If e.Delta > 0 Then
' The Camera must be in front of the window.
If (Plane1.Camera - Plane1.Window_distance) < 0.0 Then
Plane1.change_Camera_distance(20.0)
Await Plane1.process_async()
PictureBox1.Image = Nothing
GC.Collect()
PictureBox1.Image = PlaneInTermsOfGeometry.displayedBitmap
End If
Else
Plane1.change_Camera_distance(-20.0)
Await Plane1.process_async()
PictureBox1.Image = Nothing
GC.Collect()
PictureBox1.Image = PlaneInTermsOfGeometry.displayedBitmap
End If
TextBox_Kamera.Text = Math.Round(Plane1.Camera, 0).ToString(Deu)
End Sub
End Class
class PlaneInTermsOfGeometry (By the way: I was politely instructed to choose a reasonable name for this class instead of just "Plane"...)
Imports System.Windows.Media.Media3D
Imports SkiaSharp
Public NotInheritable Class PlaneInTermsOfGeometry
Private Structure VA0
Public x As Double
Public y As Double
Public z As Double
End Structure
Private A0 As VA0
Private Structure VAB
Public x As Double
Public y As Double
Public z As Double
End Structure
' →
Private AB As VAB
Private Structure VAC
Public x As Double
Public y As Double
Public z As Double
End Structure
' →
Private AC As VAC
Private ReadOnly allVectors As New List(Of Vector3D)
''' <summary>
''' in degrees
''' </summary>
Public current_x_angle As Double = 0.0
''' <summary>
''' in degrees
''' </summary>
Public current_z_angle As Double = 0.0
''' <summary>
''' The picture in which is written and which is shown by the PictureBox.
''' </summary>
Public Shared displayedBitmap As System.Drawing.Bitmap
''' <summary>
''' The camera position on the y-axis (we look along the +y arrow).
''' </summary>
Public Camera As Double = -2660.0
''' <summary>
''' The projection window position on the y-axis. Absolute value!
''' </summary>
Public Window_distance As Double = -1000.0
''' <summary>
''' The distance from the origin of coordinates to the x-length
''' </summary>
Private ReadOnly oneSide As Double
Private ReadOnly Grid As New List(Of Vector3D)
Public Sub New(ByVal A0x As Double,
ByVal A0y As Double,
ByVal A0z As Double,
ByVal ABx As Double,
ByVal ABy As Double,
ByVal ABz As Double,
ByVal ACx As Double,
ByVal ACy As Double,
ByVal ACz As Double,
ByVal enlarg As Double)
Me.A0.x = A0x
Me.A0.y = A0y
Me.A0.z = A0z
Me.AB.x = ABx * enlarg
Me.AB.y = ABy
Me.AB.z = ABz
Me.AC.x = ACx
Me.AC.y = ACy
Me.AC.z = ACz * enlarg
Me.oneSide = ABx * enlarg
For x As Double = -AB.x To AB.x Step 1.0
For z As Double = -AC.z To AC.z Step 2.0
allVectors.Add(New Vector3D(x, 0.0, z))
' For the grid
If CSng(x) Mod 15.0F = 0.0F Then
Grid.Add(New Vector3D(x, 0.0, z))
Else
Grid.Add(New Vector3D(0.0, 0.0, 0.0))
End If
Next
Next
End Sub
Public Sub change_Camera_distance(ByVal dy As Double)
Camera += dy
End Sub
Public Sub change_x_angle(ByVal value As Double)
current_x_angle += value
End Sub
Public Sub change_z_angle(ByVal value As Double)
current_z_angle += value
End Sub
Private Function rotate_around_x_axis(ByVal vec1 As Vector3D) As Vector3D
Return New Vector3D(
vec1.X,
vec1.Y * Math.Cos(current_x_angle * Math.PI / 180.0) - vec1.Z * Math.Sin(current_x_angle * Math.PI / 180.0),
vec1.Y * Math.Sin(current_x_angle * Math.PI / 180.0) + Math.Cos(current_x_angle * Math.PI / 180.0) * vec1.Z)
End Function
Private Function rotate_around_z_axis(ByVal vec2 As Vector3D) As Vector3D
Return New Vector3D(
Math.Cos(current_z_angle * Math.PI / 180.0) * vec2.X - vec2.Y * Math.Sin(current_z_angle * Math.PI / 180.0),
Math.Sin(current_z_angle * Math.PI / 180.0) * vec2.X + vec2.Y * Math.Cos(current_z_angle * Math.PI / 180.0),
vec2.Z)
End Function
Public Async Function process_async() As Task(Of Boolean)
Return Await Task.Run(Function() processing())
End Function
Private Function processing() As Boolean
displayedBitmap = Nothing
Dim i As Integer = 0
Dim imageInfo As New SKImageInfo(FormMain.PictureBox1.Size.Width, FormMain.PictureBox1.Size.Height)
Using surface As SKSurface = SKSurface.Create(imageInfo)
Using canvas As SKCanvas = surface.Canvas
canvas.Translate(FormMain.PictureBox1.Size.Width \ 2, FormMain.PictureBox1.Size.Height \ 2)
Using DarkBlue As New SKPaint With {
.TextSize = 64.0F,
.IsAntialias = True,
.Color = New SKColor(0, 64, 255),
.Style = SKPaintStyle.Fill
}
Using BrightYellow As New SKPaint With {
.TextSize = 64.0F,
.IsAntialias = True,
.Color = New SKColor(255, 255, 64),
.Style = SKPaintStyle.Fill
}
For Each vec As Vector3D In allVectors
Dim rotatedVec As Vector3D = rotate_around_z_axis(rotate_around_x_axis(vec))
If rotatedVec.Y > Window_distance Then ' The object is not further back than the window (the window is not in the object). When false, don't draw!
Dim Angle_in_degrees As Double = Vector3D.AngleBetween(
rotatedVec,
New Vector3D(rotatedVec.X, 0.0, rotatedVec.Z))
If Double.IsNaN(Angle_in_degrees) Then
i += 1
Continue For
End If
' Opposite cathetus
Dim distance_to_plane As Double = oneSide * Math.Sin(Angle_in_degrees * Math.PI / 180.0)
Dim projected As New PointF(
CSng((Camera - Window_distance) / (Camera - distance_to_plane) * rotatedVec.X),
CSng(-(Camera - Window_distance) / (Camera - distance_to_plane) * rotatedVec.Z))
If Grid(i).X = 0.0 AndAlso Grid(i).Y = 0.0 AndAlso Grid(i).Z = 0.0 Then
' draw the mathematical plane
canvas.DrawPoint(projected.X, projected.Y, DarkBlue)
Else
' draw the grid (Gitternetz)
canvas.DrawPoint(projected.X, projected.Y, BrightYellow)
End If
i += 1
End If
Next
End Using
End Using
End Using
'–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
' get the data into ‘displayedBitmap’ because the PictureBox is only accepting an usual System.Drawing.Bitmap.
'–––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––––
Using image As SKImage = surface.Snapshot()
Using data As SKData = image.Encode(SKEncodedImageFormat.Png, 100)
Using mStream As New IO.MemoryStream(data.ToArray())
displayedBitmap = New Bitmap(mStream, False)
End Using
End Using
End Using
End Using
Return True
End Function
'Koordinatenform
Public Function Cartesian_Equation() As String
Dim _N As Vector3D = Vector3D.CrossProduct(rotate_around_z_axis(New Vector3D(AB.x, AB.y, AB.z)), rotate_around_x_axis(New Vector3D(AC.x, AC.y, AC.z)))
Dim _xMinusA0 As String
Dim _yMinusA0 As String
Dim _zMinusA0 As String
If A0.x = 0.0 Then
_xMinusA0 = "x"
Else
_xMinusA0 = $"(x - {A0.x.ToString(FormMain.Deu)})"
End If
If A0.y = 0.0 Then
_yMinusA0 = "y"
Else
_yMinusA0 = $"(y - {A0.y.ToString(FormMain.Deu)})"
End If
If A0.z = 0.0 Then
_zMinusA0 = "z"
Else
_zMinusA0 = $"(z - {A0.z.ToString(FormMain.Deu)})"
End If
Return ($"{Math.Round(_N.X, 3).ToString(FormMain.Deu)} * {_xMinusA0} + {Math.Round(_N.Y, 3).ToString(FormMain.Deu)} * {_yMinusA0} + {Math.Round(_N.Z, 3).ToString(FormMain.Deu)} * {_zMinusA0}").ToString(FormMain.Deu)
End Function
End Class
For the sake of completeness, if someone wants to recreate it, here is FormNewPlane.vb to create a new plane, as shown in the first picture.
Imports Microsoft.VisualBasic.ControlChars
Public NotInheritable Class FormCreateNewPlane
Public A0x, A0y, A0z, ABx, ABy, ABz, ACx, ACy, ACz, Enlargement As Double
Private Sub FormCreateNewPlane_Load(sender As Object, e As EventArgs) Handles MyBase.Load
Me.BackColor = Color.FromArgb(184, 176, 143)
For Each but As Button In Me.Controls.OfType(Of Button)
but.BackColor = Color.FromArgb(201, 200, 193)
Next
If System.IO.File.Exists(Application.StartupPath & "\Preview.png") Then
PictureBox1.Image = Image.FromFile(Application.StartupPath & "\Preview.png")
End If
'Since this is a plane that lies in the xz plane, only the text box contents that display a 1 should be changed.
Label5.Text = $"Da es hier um eine Ebene geht, die{NewLine}in der xz-Ebene liegt, sollen nur die{NewLine}Textbox-Inhalte verändert werden,{NewLine}die eine 1 anzeigen."
End Sub
Private Sub FormCreateNewPlane_FormClosing(sender As Object, e As FormClosingEventArgs) Handles MyBase.FormClosing
If PictureBox1.Image IsNot Nothing Then PictureBox1.Image.Dispose()
End Sub
Private Sub ButtonOK_Click(sender As Object, e As EventArgs) Handles ButtonOK.Click
Me.DialogResult = DialogResult.OK
End Sub
Private Sub TextBoxA0x_TextChanged(sender As Object, e As EventArgs) Handles TextBoxA0x.TextChanged
If Double.TryParse(TextBoxA0x.Text, A0x) Then
TextBoxA0x.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxA0x.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxA0y_TextChanged(sender As Object, e As EventArgs) Handles TextBoxA0y.TextChanged
If Double.TryParse(TextBoxA0y.Text, A0y) Then
TextBoxA0y.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxA0y.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxA0z_TextChanged(sender As Object, e As EventArgs) Handles TextBoxA0z.TextChanged
If Double.TryParse(TextBoxA0z.Text, A0z) Then
TextBoxA0z.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxA0z.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxABx_TextChanged(sender As Object, e As EventArgs) Handles TextBoxABx.TextChanged
If Double.TryParse(TextBoxABx.Text, ABx) Then
TextBoxABx.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxABx.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxABy_TextChanged(sender As Object, e As EventArgs) Handles TextBoxABy.TextChanged
If Double.TryParse(TextBoxABy.Text, ABy) Then
TextBoxABy.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxABy.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxABz_TextChanged(sender As Object, e As EventArgs) Handles TextBoxABz.TextChanged
If Double.TryParse(TextBoxABz.Text, ABz) Then
TextBoxABz.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxABz.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxACx_TextChanged(sender As Object, e As EventArgs) Handles TextBoxACx.TextChanged
If Double.TryParse(TextBoxACx.Text, ACx) Then
TextBoxACx.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxACx.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxACy_TextChanged(sender As Object, e As EventArgs) Handles TextBoxACy.TextChanged
If Double.TryParse(TextBoxACy.Text, ACy) Then
TextBoxACy.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxACy.ForeColor = Color.Red
End If
End Sub
Private Sub TextBoxACz_TextChanged(sender As Object, e As EventArgs) Handles TextBoxACz.TextChanged
If Double.TryParse(TextBoxACz.Text, ACz) Then
TextBoxACz.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBoxACz.ForeColor = Color.Red
End If
End Sub
Private Sub TextBox_Enlarg_TextChanged(sender As Object, e As EventArgs) Handles TextBox_Enlarg.TextChanged
If Double.TryParse(TextBox_Enlarg.Text, Enlargement) Then
TextBox_Enlarg.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBox_Enlarg.ForeColor = Color.Red
End If
End Sub
Private Sub TextBox_Enlarg_KeyDown(sender As Object, e As KeyEventArgs) Handles TextBox_Enlarg.KeyDown
If e.KeyCode = Keys.Enter Then
If Double.TryParse(TextBox_Enlarg.Text, Enlargement) Then
TextBox_Enlarg.ForeColor = Color.FromArgb(0, 125, 0)
Else
TextBox_Enlarg.ForeColor = Color.Red
End If
Me.DialogResult = DialogResult.OK
End If
End Sub
Private Sub TextBox_Enlarg_KeyPress(sender As Object, e As KeyPressEventArgs) Handles TextBox_Enlarg.KeyPress
If e.KeyChar = Convert.ToChar(13) Then e.Handled = True ' This suppresses the ‘ding’ sound.
End Sub
End Class
If you'd like to apply perspective projection to the points, the projected point should be something like this;
Dim projected As New PointF(
CSng((Camera - Window_distance) / (Camera - rotatedVec.Y) * rotatedVec.X),
CSng(-(Camera - Window_distance) / (Camera - rotatedVec.Y) * rotatedVec.Z))
' In short, distance_to_plane = rotatedVec.Y
I am coding a program that edits pictures, I have a picture box where I load a bitmap, the first image loads fine, but if I want to load a second image, the second image won't load and the first one stays, it won't refresh. How can I do to change the image in the picture box using 2 different bitmaps?
I have PictureBox3.Image = bm where bm is a bitmap variable, it loads fine, but then if I press the other button to load another bitmap in PictureBox3 (PictureBox3.Image = bm2), it won't load.
Private Sub Button3_Click(sender As Object, e As EventArgs) Handles Button3.Click
Dim clr As Integer
Dim ymax As Integer
Dim xmax As Integer
Dim x As Integer
Dim y As Integer
Dim bm As Bitmap = PictureBox1.Image
xmax = bm.Width - 1
ymax = bm.Height - 1
For y = 0 To ymax
For x = 0 To xmax
With bm.GetPixel(x, y)
clr = 0.21 * .R + 0.72 * .G + 0.07 * .B
End With
bm.SetPixel(x, y, _
Color.FromArgb(255, clr, clr, clr))
Next x
Next y
PictureBox3.Image = bm
End Sub
Private Sub Button4_Click(sender As Object, e As EventArgs) Handles Button4.Click
Dim clr As Integer
Dim ymax As Integer
Dim xmax As Integer
Dim x As Integer
Dim y As Integer
Dim bm2 As Bitmap = PictureBox1.Image
xmax = bm2.Width - 1
ymax = bm2.Height - 1
For y = 0 To ymax
For x = 0 To xmax
With bm2.GetPixel(x, y)
clr = (1 * .R + 1 * .G + 1 * .B) / 3
End With
bm2.SetPixel(x, y, _
Color.FromArgb(255, clr, clr, clr))
Next x
Next y
PictureBox3.Image = bm2
End Sub
End Class
Dim bm2 As Bitmap = new Bitmap(PictureBox1.Image)
I am collecting data from an Arduino and transmit on Visual Basic through the serial port. Now I wanted to plot a graph with time vs electrical energy (unit kWh) - time along the x-axis and electrical energy along the y-axis. Usually I am getting data of the current from Arduino.
Now I wanted to learn how to start plotting the graph. I need a simple example explaining plotting a graph for sample. I tried some example code. It seems they are not working.
How do I plot a graph time vs current read from serial? Once Visual Basic starts running, it should save data w.r.t system time and date.
Example available here
Current code
Imports System
Imports System.IO.Ports
Imports System.ComponentModel
Imports System.Threading
Imports System.Drawing
Public Class Form1
Dim myPort As Array
Dim Distance As Integer
Private Sub Form1_Load(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles MyBase.Load
myPort = IO.Ports.SerialPort.GetPortNames()
PortComboBox.Items.AddRange(myPort)
BaudComboBox.Items.Add(9600)
BaudComboBox.Items.Add(19200)
BaudComboBox.Items.Add(38400)
BaudComboBox.Items.Add(57600)
BaudComboBox.Items.Add(115200)
ConnectButton.Enabled = True
DisconnectButton.Enabled = False
End Sub
Private Sub ConnectButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles ConnectButton.Click
SerialPort1.PortName = PortComboBox.Text
SerialPort1.BaudRate = BaudComboBox.Text
SerialPort1.Open()
Timer1.Start()
'lblMessage.Text = PortComboBox.Text & " Connected."
ConnectButton.Enabled = False
DisconnectButton.Enabled = True
End Sub
Private Sub DisconnectButton_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles DisconnectButton.Click
SerialPort1.Close()
DisconnectButton.Enabled = False
ConnectButton.Enabled = True
End Sub
Private Sub Timer1_Tick(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Timer1.Tick
Try
SerialPort1.Write("c")
System.Threading.Thread.Sleep(250)
Dim k As Double
Dim distance As String = SerialPort1.ReadLine()
k = CDbl(distance)
ListBoxSensor.Text = k
Catch ex As Exception
End Try
End Sub
Private Sub Relay_ON_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Relay_ON.Click
SerialPort1.Write("1")
End Sub
Private Sub Relay_Off_Click(ByVal sender As System.Object, ByVal e As System.EventArgs) Handles Relay_Off.Click
SerialPort1.Write("0")
End Sub
End Class
Add a picturebox, a timer a button and a textbox:
PictureBox1 size = 768, 279
timer interval to 500
Private img As Bitmap
Private imgClone As Bitmap
Private widthInterval As Integer
'the distance from the left side of picturebox where x axis starts
Private leftPad As Integer = 50
'the distance from the down side of picturebox where x axis is
Private downPad As Integer = 30
'the distance from the up side of picturebox where y axis ends
Private upPad As Integer = 50
'the distance from the right side of picturebox where x axis ends
Private rightPad As Integer = 80
Private rn As New Random
Private Sub Button1_Click(sender As System.Object, e As System.EventArgs) Handles Button1.Click
drawBack()
Timer1.Enabled = True
End Sub
Private Sub drawBack()
Static count As Boolean = False
Dim g As Graphics
'number of values in x axis e.g 1, 2, 3, ... representing time
Dim numX As Integer = 23
'number of values in y axis representing KW/h
Dim numY As Integer = 5
Dim stringFormat As New StringFormat()
'arreys to hold the text for both axies
Dim arrayTextX(numX), arrayTextY(numY - 1) As String
Dim i As Integer
'the distance from the right side of picturebox where x axis stops
Dim rightPad As Integer = 80
Dim brush As Brush = New SolidBrush(Color.FromArgb(245, 255, 255))
Dim pen As Pen = New Pen(Color.FromArgb(212, 212, 212), 1)
Dim height, x, y As Integer
'Run once
If count = True Then
Return
End If
count = True
stringFormat.Alignment = StringAlignment.Center
img = New Bitmap(PictureBox1.Width, PictureBox1.Height)
imgClone = New Bitmap(PictureBox1.Width, PictureBox1.Height)
g = Graphics.FromImage(img)
g.SmoothingMode = SmoothingMode.AntiAlias
g.Clear(Color.White)
'the distance in x axis between each value
widthInterval = CInt((PictureBox1.Width - leftPad - rightPad) / (numX + 1))
'the distance in y axis between each value
height = CInt((PictureBox1.Height - upPad - downPad) / (numY + 1))
'fill arrays with text
For i = 0 To numX - 1
arrayTextX(i) = (i + 1).ToString
Next
For i = 0 To numY - 1
arrayTextY(i) = ((i + 1) * height).ToString
Next
'fill background of graph with color
g.FillRectangle(brush, New Rectangle(leftPad, upPad, PictureBox1.Width - leftPad - rightPad + 1, _
PictureBox1.Height - downPad - upPad))
'vertical lines
x = leftPad
For i = 0 To numX - 1
x += widthInterval
g.DrawLine(pen, x, PictureBox1.Height - downPad, x, upPad)
g.DrawString(arrayTextX(i), New Font("Arial", 8), Brushes.Black, _
New Rectangle(x - 10, PictureBox1.Height - downPad + 3, 20, 20), stringFormat)
Next
'horizontal lines
stringFormat.Alignment = StringAlignment.Far
y = PictureBox1.Height - downPad
For i = 0 To numY - 1
y -= height
g.DrawLine(pen, leftPad, y, PictureBox1.Width - rightPad, y)
g.DrawString(arrayTextY(i), New Font("Arial", 8), Brushes.Black, _
New Rectangle(0, y - 6, leftPad - 5, 20), stringFormat)
Next
g.DrawString("KW/Hour", New Font("Arial", 8, FontStyle.Bold), Brushes.Black, _
New PointF(5, 5))
g.DrawString("Time", New Font("Arial", 8, FontStyle.Bold), Brushes.Black, _
New PointF(PictureBox1.Width - 50, PictureBox1.Height - 20))
'draws x axis
g.DrawLine(Pens.Black, New Point(leftPad, PictureBox1.Height - downPad), _
New Point(PictureBox1.Width - rightPad, PictureBox1.Height - downPad))
'draws y axis
g.DrawLine(Pens.Black, New Point(leftPad, PictureBox1.Height - downPad), _
New Point(leftPad, upPad))
g.Dispose()
PictureBox1.Image = img
imgClone = CType(img.Clone, Bitmap)
End Sub
Private Sub Timer1_Tick(sender As System.Object, e As System.EventArgs) Handles Timer1.Tick
Dim value, x As Integer
Dim g As Graphics
Dim pntEnd As Point
Static pnt As Point = New Point(-1, -1)
Static staticX As Integer = -1
Dim hour As Integer = DateTime.Now.Hour
Dim minute As Integer = DateTime.Now.Minute
Dim second As Integer = DateTime.Now.Second
second = minute * 60 + second
x = leftPad + hour * widthInterval + CInt(CDbl(widthInterval - 1) * CDbl(second) / 3600.0R)
If pnt.X >= 0 Then
'checks if the new points x coordinate is the same as the previous and returns
If x <= staticX Then
Return
End If
End If
GetValue(value)
pntEnd = New Point(x, PictureBox1.Height - value - downPad)
g = Graphics.FromImage(img)
g.SmoothingMode = SmoothingMode.AntiAlias
If pnt.X < 0 Then
g.DrawLine(Pens.Red, pntEnd, pntEnd)
Else
g.DrawLine(Pens.Red, pnt, pntEnd)
End If
g.Dispose()
pnt = pntEnd
staticX = x
PictureBox1.Invalidate()
End Sub
Private Sub GetValue(ByRef value As Integer)
'here you can take the value from arduino.
value = rn.Next(0, PictureBox1.Height - downPad - upPad) 'random value
End Sub
When you press Button1 the graph starts.
Calculate width of graph (x axis)
width = PictureBox1.Width - leftPad - rightPad
this width is equivelant with 24h or 86400sec. So you should set the timer interval to
Timer1.Interval = CInt((86400 / width ) * 1000) 'in milliseconds
There is no need to be that because the tick function checks if the
new point is the same as the previous. So set timer interval to 1 second.
So I'm deliberately trying to make a Download ETA Calculator using Visual Basic 2013 Ultimate.. but after 3 hours of work, I tried running it but it won't show the final result (The Estimated Time). I am also asking you how to convert the result into Time format..
here is the code
Public Class Form1
Private Property z As Object
Private Sub Label1_Click(sender As Object, e As EventArgs)
End Sub
Private Sub Button2_Click(sender As Object, e As EventArgs)
End Sub
Private Sub LinkLabel1_LinkClicked(sender As Object, e As
LinkLabelLinkClickedEventArgs) Handles LinkLabel1.LinkClicked
Process.Start("www.speedtest.net")
End Sub
Private Sub Button1_Click(sender As Object, e As EventArgs)
Handles Button1.Click
Dim x, y, z, a As Integer
Dim sum
x = TextBox1.Text
y = TextBox2.Text
sum = Label1
If RadioButton1.Checked = True And RadioButton3.Checked = True Then
z = x / 1024 / y
a = z / 60
sum = a / 60
End If
If RadioButton1.Checked = True And RadioButton4.Checked = True Then
z = x / 1024 / y
a = z / 60 * 1024
sum = a / 60
End If
If RadioButton2.Checked = True And RadioButton3.Checked = True Then
z = x / 1048576 / y
a = z / 60
sum = a / 60
End If
If RadioButton2.Checked = True And RadioButton4.Checked = True Then
z = x / 1048576 / y
a = z / 60 * 1024
sum = a / 60
End If
End Sub
Private Sub RadioButton1_CheckedChanged(sender As Object, e As EventArgs)
Handles
RadioButton1.CheckedChanged
End Sub
End Class
Error 2
http://tny.cz/7b5711f7
Error 3
http://tny.cz/09bf1f96
Dim sum
sum = Label1
Presumably Label1 is a label control so you're setting a variable to be equal to the label control.
Later on, you're trying to set this variable of type label control to a decimal
sum = a / 60
I would say you want probably want to replace all your
sum = a / 60
with something like
label1.Text = New TimeSpan(a / 60, 0, 0).ToString()
and forget about variable sum all together
I have an grayscale image, I have been a able to display a rectangle on the image to extract the ROI and compute the standard deviation and mean. However, when I'm moving the rectangle around, i notice I have the wrong values for the image, especially where the image is entirely black. At this area, i should be getting a zero for the mean and standard deviation. However, im obtaining a 0 for the mean and negative values for the standard deviation and other point of this black area the mean increases to the mean the same as light dominated areas. I have been struggling to come up with a solution. Are there any ideas to help. I'll be grateful. My code for the mousemove button and mean and standard deviation are posted below. Thanks.
Private Sub PictureBox1_MouseDown(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseDown
Dim mean As Double = 0
Dim meancount As Integer = 0
Dim bmap As New Bitmap(400, 400)
bmap = PictureBox1.Image
Dim colorpixel As Color = bmap.GetPixel(e.X, e.Y)
' Dim pixels As Double = colorpixel.R + colorpixel.G + colorpixel.B
If e.Button = Windows.Forms.MouseButtons.Left AndAlso Rect.Contains(e.Location) Then
If (PictureBox1.Image Is Nothing) Or (PictureBox1.Height - (e.Y + SquareHeight) < 0) Or (PictureBox1.Width - (e.X + SquareWidth) < 0) Then
Else
Dim ROI As New Bitmap(400, 400)
Dim x As Integer = 0
Dim countx As Integer = 0
Dim county As Integer = 0
For i = e.X To (e.X + SquareWidth)
For j = (e.Y + x) To (e.Y + SquareHeight)
Dim pixelcolor As Color = bmap.GetPixel(i, j)
ROI.SetPixel(countx, county, pixelcolor)
mean = mean + pixelcolor.R + pixelcolor.G + pixelcolor.B
county += 1
meancount += 1
Next
county = 0
countx += 1
x = x + 1
Next
mean = mean / meancount
Dim SD = mean - 75
Dim area As Integer = (SquareHeight * SquareWidth)
Dim anotherForm As Form2
anotherForm = New Form2(mean, SD, area, 34)
anotherForm.Show()
End If
End If
' Catch ex As Exception
' MessageBox.Show(ex.Message())
' End Try
End Sub
Private Sub PictureBox1_MouseMove(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseMove
Rect.X = e.X + x
Rect.Y = e.Y + y
Rect.Width = SquareWidth
Rect.Height = SquareHeight
' Label1.Text = "XRect: " + Rect.X.ToString() + " YRect: " + Rect.Y.ToString() + " Xmouse " + e.X.ToString() + " Ymouse " + e.Y.ToString()
PictureBox1.Refresh()
End Sub
Private Sub PictureBox1_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles PictureBox1.Paint
e.Graphics.DrawRectangle(Pens.Red, Rect)
End Sub
Private Function StandardDeviation(ByVal image As Bitmap, ByVal mean As Double, ByVal meancount As Integer) As Double
Dim SD(SquareHeight * SquareWidth) As Double
Dim count As Integer = 0
For i = 0 To SquareWidth
For j = 0 To SquareHeight
Dim pixelcolor As Color = image.GetPixel(i, j)
SD(count) = Double.Parse(pixelcolor.R) + Double.Parse(pixelcolor.G) + Double.Parse(pixelcolor.B) - mean
count += 1
Next
Next
Dim SDsum As Double = 0
For i = 0 To count
SDsum = SDsum + SD(i)
Next
SDsum = SDsum / (SquareHeight * SquareWidth)
SDsum = ((SDsum) ^ (1 / 2))
Return SDsum
End Function
Private Sub PictureBox1_MouseClick(ByVal sender As System.Object, ByVal e As System.Windows.Forms.MouseEventArgs) Handles PictureBox1.MouseClick
Dim P As Point = e.Location
P = New Point
End Sub
You should calc mean like
mean = mean / (meancount * 3) (there is 3 colors added) and it is better to calc running mean instead of summing all and divide later. I guess there can be more math errors.