3d graph

3-dimensional Graphs


Imports System.Drawing
Imports System.Math
Imports System.Data

Public Class Form2
    Const PI As Double = 3.141593
    Const FREQ As Integer = 40
    Const CLIP As Boolean = True

    Dim XMIN As Double = -PI
    Dim XMAX As Double = PI
    Dim YMIN As Double = -PI
    Dim YMAX As Double = PI
    Dim ZMIN As Double = -PI
    Dim ZMAX As Double = PI

    Dim equation As String = "SIN(X) - COS(Z)"
    Dim LZX(FREQ) As Single
    Dim LZY(FREQ) As Single

    Dim compiledExpr As Func(Of Double, Double, Double)

    Private Sub Form1_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        Me.Text = "3D Graph II - VB.NET"
        Me.ClientSize = New Size(900, 650)
        Me.Location = New Point(275, 75)
        DoubleBuffered = True

        Dim lbl As New Label With {.Text = "Y =", .Top = 10, .Left = 10, .Width = 40, .Height = 20, .TextAlign = ContentAlignment.MiddleLeft}
        Dim box As New TextBox With {.Name = "EquationBox", .Text = equation, .Top = 10, .Left = 60, .Width = 400}
        Dim btn As New Button With {.Text = "Draw", .Top = 10, .Left = 470, .Height = 20}

        AddHandler btn.Click, Sub()
                                  equation = box.Text
                                  Try
                                      compiledExpr = CompileExpression(equation)
                                      Invalidate()
                                  Catch ex As Exception
                                      MessageBox.Show("Error compiling expression: " & ex.Message)
                                  End Try
                              End Sub

        Controls.AddRange({lbl, box, btn})

        ' Precompile once
        compiledExpr = CompileExpression(equation)
    End Sub

    Private Sub Form1_Paint(sender As Object, e As PaintEventArgs) Handles Me.Paint
        Dim bmp = New Bitmap(ClientSize.Width, ClientSize.Height)
        Using g As Graphics = Graphics.FromImage(bmp)
            g.SmoothingMode = Drawing2D.SmoothingMode.HighSpeed
            g.Clear(Color.Black)
            DrawGraph(g)
        End Using
        e.Graphics.DrawImage(bmp, 0, 0)
    End Sub

    ' ---------- Drawing Functions ----------

    Private Sub DrawGraph(g As Graphics)
        ' Define margins
        Dim marginLeft As Integer = 50
        Dim marginTop As Integer = 60
        Dim marginRight As Integer = 50
        Dim marginBottom As Integer = 40

        Dim plotWidth As Integer = Me.ClientSize.Width - marginLeft - marginRight
        Dim plotHeight As Integer = Me.ClientSize.Height - marginTop - marginBottom

        ' Logical bounds with buffer space
        Dim XSMIN = XMIN - 0.25 * (XMAX - XMIN)
        Dim XSMAX = XMAX + 0.25 * (XMAX - XMIN)
        Dim YSMIN = YMIN - 0.25 * (YMAX - YMIN)
        Dim YSMAX = YMAX + 0.25 * (YMAX - YMIN)

        ' Graphing loop
        For z As Double = ZMAX To ZMIN Step -((ZMAX - ZMIN) / FREQ)
            Dim q As Integer = 0
            For x As Double = XMIN To XMAX Step (XMAX - XMIN) / FREQ
                q += 1
                Dim LX = LZX(q)
                Dim LY = LZY(q)

                LZX(q) = CSng(AdjustX(x, z))
                Dim y As Double
                Try
                    y = compiledExpr(x, z)
                Catch
                    y = 0
                End Try

                If CLIP Then y = Math.Max(YMIN, Math.Min(YMAX, y))

                LZY(q) = CSng(AdjustY(y, z))

                If q = 1 Then
                    LZX(q - 1) = LZX(q)
                    LZY(q - 1) = LZY(q)
                End If

                Dim col As Color = ColorFromY(y)
                Using p As New Pen(col)
                    g.DrawLine(p,
                    ToScreenX(LZX(q - 1), XSMIN, XSMAX, plotWidth, marginLeft),
                    ToScreenY(LZY(q - 1), YSMIN, YSMAX, plotHeight, marginTop),
                    ToScreenX(LZX(q), XSMIN, XSMAX, plotWidth, marginLeft),
                    ToScreenY(LZY(q), YSMIN, YSMAX, plotHeight, marginTop))

                    If z <> ZMAX Then
                        g.DrawLine(p,
                        ToScreenX(LX, XSMIN, XSMAX, plotWidth, marginLeft),
                        ToScreenY(LY, YSMIN, YSMAX, plotHeight, marginTop),
                        ToScreenX(LZX(q), XSMIN, XSMAX, plotWidth, marginLeft),
                        ToScreenY(LZY(q), YSMIN, YSMAX, plotHeight, marginTop))
                    End If
                End Using
            Next
        Next
    End Sub

    ' ---------- Helpers ----------

    Private Function AdjustX(x As Double, z As Double) As Double
        Return z * 0.5 + x
    End Function

    Private Function AdjustY(y As Double, z As Double) As Double
        Return z * 0.5 + y
    End Function

    Private Function ToScreenX(x As Double, xmin As Double, xmax As Double, width As Integer, leftMargin As Integer) As Single
        Return CSng((x - xmin) / (xmax - xmin) * width + leftMargin)
    End Function

    Private Function ToScreenY(y As Double, ymin As Double, ymax As Double, height As Integer, topMargin As Integer) As Single
        Return CSng(topMargin + (1 - (y - ymin) / (ymax - ymin)) * height)
    End Function

    Private Function ColorFromY(y As Double) As Color
        Dim factor = (y - YMIN) / (YMAX - YMIN)
        factor = Math.Max(0, Math.Min(1, factor))
        Return Color.FromArgb(255, CInt(255 * factor), 0, CInt(255 * (1 - factor)))
    End Function

    ' ---------- Expression Compilation ----------

    Private Function CompileExpression(expr As String) As Func(Of Double, Double, Double)
        Dim code As String = expr.ToUpper().
            Replace("SIN", "Math.Sin").
            Replace("COS", "Math.Cos").
            Replace("TAN", "Math.Tan").
            Replace("ATN", "Math.Atan").
            Replace("EXP", "Math.Exp").
            Replace("LOG", "Math.Log").
            Replace("SQR", "Math.Sqrt").
            Replace("ABS", "Math.Abs").
            Replace("INT", "Math.Floor").
            Replace("SGN", "Math.Sign").
            Replace("PI", PI.ToString()).
            Replace("X", "{0}").
            Replace("Z", "{1}")

        Dim formatted = $"Return {String.Format(code, "x", "z")}"
        Dim methodCode = $"
Imports System
Imports Microsoft.VisualBasic
Public Module DynamicExpr
    Public Function Eval(x As Double, z As Double) As Double
        {formatted}
    End Function
End Module"

        Dim provider = CodeDom.Compiler.CodeDomProvider.CreateProvider("VB")
        Dim parms = New CodeDom.Compiler.CompilerParameters With {
            .GenerateInMemory = True,
            .GenerateExecutable = False
        }

        parms.ReferencedAssemblies.Add("System.dll")

        Dim results = provider.CompileAssemblyFromSource(parms, methodCode)
        If results.Errors.HasErrors Then
            Throw New Exception("Syntax Error: " & results.Errors(0).ErrorText)
        End If

        Dim asm = results.CompiledAssembly
        Dim mi = asm.GetType("DynamicExpr").GetMethod("Eval")
        Return Function(x, z) CDbl(mi.Invoke(Nothing, New Object() {x, z}))
    End Function

End Class

Download '3-dimensional Graphs':

📥 Download 3-dimensional-graphs.vb