Questo sito utilizza cookies solo per scopi di autenticazione sul sito e nient'altro. Nessuna informazione personale viene tracciata. Leggi l'informativa sui cookies.
Username: Password: oppure
MGraphing - GraphArea.vb

GraphArea.vb

Caricato da: Totem
Scarica il programma completo

  1. Imports MGraphing.GraphItems
  2. Imports System.Text.RegularExpressions
  3. Imports System.CodeDom.Compiler
  4.  
  5. 'Written by Totem
  6.  
  7. Public Class GraphArea
  8.     Private Structure MethodInfoPlus
  9.         Dim Method As Reflection.MethodInfo
  10.         Dim Target As Object
  11.     End Structure
  12.  
  13.     Private _Items As List(Of GraphItemBase)
  14.     Private EssentialItems As List(Of GraphItemBase)
  15.     Private _Center As Point
  16.     Private _AxisColor, _FunctionColor, _GridLinesColor As Color
  17.     Private _PixelsPerDot As Int32
  18.     Private _StartInZero, _AccurateLine, _ShowGridLines As Boolean
  19.     Private _DrawValues, _LaunchExceptionOnDrawError As Boolean
  20.     Private _DrawValueIncrement As Single
  21.  
  22.     Private EvaluateX As Boolean = True
  23.     'Queste servono per salvare l'immagine in seguito
  24.     Private AssociatedImage As Bitmap
  25.     Private AssociatedGraphic As Graphics = Nothing
  26.  
  27.     Sub New()
  28.         Me.InitializeComponent()
  29.         Me.AxisColor = Color.Black
  30.         Me.FunctionColor = Color.Red
  31.         Me.Center = New Point(Me.Width / 3, Me.Height / 3)
  32.         Me.PixelsPerDot = 5
  33.         Me.StartInZero = False
  34.         Me.AccurateLine = False
  35.         Me.DrawValues = False
  36.         Me._DrawValueIncrement = 10
  37.         Me.LaunchExceptionOnDrawError = True
  38.         Me.ShowGridLines = False
  39.  
  40.         _Items = New List(Of GraphItemBase)
  41.         EssentialItems = New List(Of GraphItemBase)
  42.     End Sub
  43.  
  44.     ''' <summary>
  45.     ''' Tutti gli elementi da disegnare nel grafico.
  46.     ''' </summary>
  47.     Public ReadOnly Property Items() As List(Of GraphItemBase)
  48.         Get
  49.             Return _Items
  50.         End Get
  51.     End Property
  52.  
  53.     ''' <summary>
  54.     ''' Le coordinate del centro degli assi cartesiani.
  55.     ''' </summary>
  56.     Public Property Center() As Point
  57.         Get
  58.             Return _Center
  59.         End Get
  60.         Set(ByVal Value As Point)
  61.             _Center = Value
  62.         End Set
  63.     End Property
  64.  
  65.     ''' <summary>
  66.     ''' Il colore con cui disegnare gli assi cartesiani.
  67.     ''' </summary>
  68.     Public Property AxisColor() As Color
  69.         Get
  70.             Return _AxisColor
  71.         End Get
  72.         Set(ByVal Value As Color)
  73.             _AxisColor = Value
  74.         End Set
  75.     End Property
  76.  
  77.     ''' <summary>
  78.     ''' Il colore con cui disegnare la funzione.
  79.     ''' </summary>
  80.     Public Property FunctionColor() As Color
  81.         Get
  82.             Return _FunctionColor
  83.         End Get
  84.         Set(ByVal Value As Color)
  85.             _FunctionColor = Value
  86.         End Set
  87.     End Property
  88.  
  89.     ''' <summary>
  90.     ''' Il colore con cui disegnare la griglia del grafico.
  91.     ''' </summary>
  92.     Public Property GridLinesColor() As Color
  93.         Get
  94.             Return _GridLinesColor
  95.         End Get
  96.         Set(ByVal Value As Color)
  97.             _GridLinesColor = Value
  98.         End Set
  99.     End Property
  100.  
  101.     ''' <summary>
  102.     ''' Determina quanti pixel cosituiscono un punto.
  103.     ''' </summary>
  104.     Public Property PixelsPerDot() As Int32
  105.         Get
  106.             Return _PixelsPerDot
  107.         End Get
  108.         Set(ByVal Value As Int32)
  109.             _PixelsPerDot = Value
  110.         End Set
  111.     End Property
  112.  
  113.     ''' <summary>
  114.     ''' Determina se la funzione inizia in (0;0) automaticamente.
  115.     ''' </summary>
  116.     Public Property StartInZero() As Boolean
  117.         Get
  118.             Return _StartInZero
  119.         End Get
  120.         Set(ByVal Value As Boolean)
  121.             _StartInZero = Value
  122.         End Set
  123.     End Property
  124.  
  125.     ''' <summary>
  126.     ''' Determina se conservare le coordinate decimali fino all'ultimo per poi convertirle in interi. In questo
  127.     ''' modo viene ridotto l'errore di approssimazione.
  128.     ''' </summary>
  129.     Public Property AccurateLine() As Boolean
  130.         Get
  131.             Return _AccurateLine
  132.         End Get
  133.         Set(ByVal Value As Boolean)
  134.             _AccurateLine = Value
  135.         End Set
  136.     End Property
  137.  
  138.     ''' <summary>
  139.     ''' Determina se disegnare anche i valori sugli assi.
  140.     ''' </summary>
  141.     Public Property DrawValues() As Boolean
  142.         Get
  143.             Return _DrawValues
  144.         End Get
  145.         Set(ByVal Value As Boolean)
  146.             _DrawValues = Value
  147.         End Set
  148.     End Property
  149.  
  150.     ''' <summary>
  151.     ''' Determina ogni quanto disegnare i valori sugli assi.
  152.     ''' </summary>
  153.     Public Property DrawValueIncrement() As Single
  154.         Get
  155.             Return _DrawValueIncrement
  156.         End Get
  157.         Set(ByVal Value As Single)
  158.             If DrawValues Or ShowGridLines Then
  159.                 If Value > 0 Then
  160.                     _DrawValueIncrement = Value
  161.                 Else
  162.                     _DrawValueIncrement = 10
  163.                 End If
  164.             End If
  165.         End Set
  166.     End Property
  167.  
  168.     ''' <summary>
  169.     ''' Determina se viene visualizzato un messaggio di errore quando, nella fase di disegno, vengono
  170.     ''' passati parametri scorretti alle funzioni oppure si va in overflow.
  171.     ''' </summary>
  172.     Public Property LaunchExceptionOnDrawError() As Boolean
  173.         Get
  174.             Return _LaunchExceptionOnDrawError
  175.         End Get
  176.         Set(ByVal Value As Boolean)
  177.             _LaunchExceptionOnDrawError = Value
  178.         End Set
  179.     End Property
  180.  
  181.     ''' <summary>
  182.     ''' Determina se disegnare anche la griglia del grafico.
  183.     ''' </summary>
  184.     Public Property ShowGridLines() As Boolean
  185.         Get
  186.             Return _ShowGridLines
  187.         End Get
  188.         Set(ByVal Value As Boolean)
  189.             _ShowGridLines = Value
  190.         End Set
  191.     End Property
  192.  
  193.     Private Function GetValueOnX(ByVal Value As Single) As GraphItemBase
  194.         Dim Position As New Point(Center.X + (Value * Me.PixelsPerDot), Center.Y)
  195.         Dim ValueName As New GraphString(Position, Value.ToString, Me.Font)
  196.         Return ValueName
  197.     End Function
  198.  
  199.     Private Function GetValueOnY(ByVal Value As Single) As GraphItemBase
  200.         Dim Position As New Point(Center.X, Center.Y - (Value * Me.PixelsPerDot))
  201.         Dim ValueName As New GraphString(Position, Value.ToString, Me.Font)
  202.         Return ValueName
  203.     End Function
  204.  
  205.     'Gran parte della funzione che segue e' stata presa da un libro
  206.     'sulla programmazione in VB2005 di Francesco Balena, tuttavia ho apportato alcune
  207.     'modifiche per adattarla al mio codice
  208.     Private Function CreateEvaluator(ByVal Expression As String) As MethodInfoPlus
  209.         Dim RealExpression As String = Expression
  210.         Dim FunctionX As New Regex("(?<function>\w)\s*=\s*")
  211.         Dim M As Match = FunctionX.Match(Expression)
  212.  
  213.         If M.Success Then
  214.             If M.Groups("function").Value.ToLower = "y" Then
  215.                 EvaluateX = True
  216.             Else
  217.                 EvaluateX = False
  218.             End If
  219.         Else
  220.             Throw New ArgumentException("Espressione non valida!")
  221.         End If
  222.  
  223.         If Expression.IndexOf("=") > -1 Then
  224.             RealExpression = Expression.Remove(0, Expression.IndexOf("=") + 1)
  225.         End If
  226.  
  227.         Dim Code As String = _
  228.         "Imports Microsoft.VisualBasic" & vbCrLf & _
  229.         "Imports System" & vbCrLf & _
  230.         "Imports System.Math" & vbCrLf & _
  231.         "Public Class Evaluator" & vbCrLf & _
  232.         "    Public Function Evaluate(ByVal X As Single) As Single" & vbCrLf & _
  233.         "        Return " & RealExpression & vbCrLf & _
  234.         "    End Function" & vbCrLf & _
  235.         "End Class" & vbCrLf
  236.  
  237.         If Not EvaluateX Then
  238.             Code = Code.Replace("X", "Y")
  239.         End If
  240.  
  241.         Dim Parameters As New CodeDom.Compiler.CompilerParameters
  242.         With Parameters
  243.             .GenerateExecutable = False
  244. #If DEBUG Then
  245.             .IncludeDebugInformation = True
  246.             .TempFiles.KeepFiles = True
  247.             .GenerateInMemory = False
  248. #Else
  249.             .TreatWarningsAsErrors = True
  250.             .TempFiles.KeepFiles = False
  251.             .GenerateInMemory = True
  252. #End If
  253.             .ReferencedAssemblies.Add("Microsoft.VisualBasic.dll")
  254.             .ReferencedAssemblies.Add("System.dll")
  255.         End With
  256.  
  257.         Dim Provider As New VBCodeProvider
  258.         Dim CompResults As CompilerResults = Provider.CompileAssemblyFromSource(Parameters, Code)
  259.  
  260.         If CompResults.Errors.Count > 0 Then
  261.             Dim Msg As String = ""
  262.             For Each Err As CompilerError In CompResults.Errors
  263.                 Msg &= Err.ToString & vbCrLf
  264.             Next
  265.             'MsgBox(Msg, MsgBoxStyle.Critical)
  266.             Throw New ArgumentException("Espressione non valida!")
  267.         Else
  268.             Dim Asm As Reflection.Assembly = CompResults.CompiledAssembly
  269.             Dim Evaluator As Object = Asm.CreateInstance("Evaluator")
  270.             Dim EvalMethod As Reflection.MethodInfo = Evaluator.GetType.GetMethod("Evaluate")
  271.             Dim Result As MethodInfoPlus
  272.             Result.Method = EvalMethod
  273.             Result.Target = Evaluator
  274.             Return Result
  275.         End If
  276.     End Function
  277.  
  278.     Private Function Evaluate(ByVal Method As MethodInfoPlus, ByVal Value As Single) As Single
  279.         Dim Args() As Object = {Value}
  280.         Dim Result As Object = Method.Method.Invoke(Method.Target, Args)
  281.         Return CSng(Result)
  282.     End Function
  283.  
  284.     Public Sub DrawFunction(ByVal Expression As String, ByVal Min As Single, ByVal Max As Single, ByVal Increment As Single)
  285.         Dim X, Y As Single
  286.         Dim OldX, OldY As Single
  287.         Dim Item As GraphLine
  288.         Dim ExactItem As ExactGraphLine
  289.         Dim Evaluator As MethodInfoPlus = CreateEvaluator(Expression)
  290.  
  291.         Me.Items.Clear()
  292.  
  293.         For Value As Single = Min To Max Step Increment
  294.             OldX = X
  295.             OldY = Y
  296.  
  297.             If EvaluateX Then
  298.                 X = Value
  299.                 Y = Evaluate(Evaluator, X)
  300.             Else
  301.                 Y = Value
  302.                 X = Evaluate(Evaluator, Y)
  303.             End If
  304.  
  305.             If (Not StartInZero) And (OldX = 0 And OldY = 0) And Value = Min Then
  306.                 OldX = X
  307.                 OldY = Y
  308.             End If
  309.  
  310.             If Me.AccurateLine Then
  311.                 ExactItem = New ExactGraphLine(OldX, OldY, X, Y)
  312.                 ExactItem.Color = Me.FunctionColor
  313.                 ExactItem.ToPixel(Me.PixelsPerDot)
  314.                 ExactItem.SetAbsolutePosition(Me.Center)
  315.                 ExactItem.SetAbsoluteEndPoint(Me.Center)
  316.                 Me.Items.Add(ExactItem)
  317.             Else
  318.                 Item = New GraphLine(New Point(OldX, OldY), New Point(X, Y))
  319.                 Item.Color = Me.FunctionColor
  320.                 Item.ToPixel(Me.PixelsPerDot)
  321.                 Item.Position = Item.GetAbsolutePosition(Me.Center)
  322.                 Item.EndPoint = Item.GetAbsoluteEndPoint(Me.Center)
  323.                 Me.Items.Add(Item)
  324.             End If
  325.         Next
  326.  
  327.         Me.Refresh()
  328.     End Sub
  329.  
  330.     Public Sub Save()
  331.         Dim FSave As New SaveFileDialog
  332.         FSave.Filter = "File Bitmap|*.bmp"
  333.         If FSave.ShowDialog = DialogResult.OK Then
  334.             AssociatedGraphic = Graphics.FromImage(AssociatedImage)
  335.             AssociatedImage.Save(FSave.FileName)
  336.         End If
  337.     End Sub
  338.  
  339.     Public Sub RedrawEssentialItems()
  340.         Dim Line As GraphLine
  341.         Dim Value As GraphString
  342.  
  343.         EssentialItems.Clear()
  344.  
  345.         With EssentialItems
  346.             If Me.DrawValueIncrement = 0 Then
  347.                 MessageBox.Show("DrawValueIncrement ha valore 0! Il rendering è stato interrotto poichè tale valore avrebbe portato " & _
  348.                 "l'applicazione ad un crash.", "MGraphing", MessageBoxButtons.OK, MessageBoxIcon.Exclamation)
  349.                 Exit Sub
  350.             End If
  351.  
  352.             'Valori
  353.             If Me.DrawValues Then
  354.                 For X As Single = 0 To (Me.Width / Me.PixelsPerDot) Step Me.DrawValueIncrement
  355.                     Value = GetValueOnX(X)
  356.                     .Add(Value)
  357.                     Value = GetValueOnX(-X)
  358.                     .Add(Value)
  359.                 Next
  360.                 For Y As Single = 0 To (Me.Height / Me.PixelsPerDot) Step Me.DrawValueIncrement
  361.                     Value = GetValueOnY(Y)
  362.                     .Add(Value)
  363.                     Value = GetValueOnY(-Y)
  364.                     .Add(Value)
  365.                 Next
  366.             End If
  367.             'MsgBox(Me.ShowGridLines & " " & Me.DrawValueIncrement)
  368.  
  369.             'Griglia
  370.             If Me.ShowGridLines Then
  371.                 For X As Single = 0 To (Me.Width / Me.PixelsPerDot) Step Me.DrawValueIncrement
  372.                     Line = New GraphLine(New Point(Center.X + (X * Me.PixelsPerDot), 0), New Point(Center.X + (X * Me.PixelsPerDot), Me.Height))
  373.                     Line.Color = Me.GridLinesColor
  374.                     .Add(Line)
  375.                     Line = New GraphLine(New Point(Center.X - (X * Me.PixelsPerDot), 0), New Point(Center.X - (X * Me.PixelsPerDot), Me.Height))
  376.                     Line.Color = Me.GridLinesColor
  377.                     .Add(Line)
  378.                 Next
  379.                 For Y As Single = 0 To (Me.Height / Me.PixelsPerDot) Step Me.DrawValueIncrement
  380.                     Line = New GraphLine(New Point(0, Center.Y - (Y * Me.PixelsPerDot)), New Point(Me.Width, Center.Y - (Y * Me.PixelsPerDot)))
  381.                     Line.Color = Me.GridLinesColor
  382.                     .Add(Line)
  383.                     Line = New GraphLine(New Point(0, Center.Y + (Y * Me.PixelsPerDot)), New Point(Me.Width, Center.Y + (Y * Me.PixelsPerDot)))
  384.                     Line.Color = Me.GridLinesColor
  385.                     .Add(Line)
  386.                 Next
  387.             End If
  388.  
  389.             'Asse X
  390.             Line = New GraphLine(New Point(0, Center.Y), New Point(Me.Width, Center.Y))
  391.             Line.Color = Me.AxisColor
  392.             .Add(Line)
  393.  
  394.             'Asse Y
  395.             Line = New GraphLine(New Point(Center.X, 0), New Point(Center.X, Me.Height))
  396.             Line.Color = Me.AxisColor
  397.             .Add(Line)
  398.  
  399.         End With
  400.     End Sub
  401.  
  402.     Public Overrides Sub Refresh()
  403.         RedrawEssentialItems()
  404.         MyBase.Refresh()
  405.     End Sub
  406.  
  407.     'Da perfezionare...
  408.     Public Sub DoAxialSymmetry(ByVal Parameter As Char, ByVal Constant As Single)
  409.         If Parameter = "x" Then
  410.             Dim Line As GraphLine
  411.             Dim ELine As ExactGraphLine
  412.             Dim Temp As New List(Of GraphItemBase)
  413.             For Each GenericItem As GraphItemBase In Me.Items
  414.                 If (TypeOf GenericItem Is GraphLine) Then
  415.                     Line = CType(GenericItem, GraphLine).Clone
  416.                     Line.Position = New Point(2 * Constant - Line.Position.X, Line.Position.Y)
  417.                     Line.EndPoint = New Point(2 * Constant - Line.EndPoint.X, Line.Position.Y)
  418.                     Temp.Add(Line)
  419.                 ElseIf (TypeOf GenericItem Is ExactGraphLine) Then
  420.                     ELine = CType(GenericItem, ExactGraphLine)
  421.                     ELine.StartX = 2 * Constant - ELine.StartX
  422.                     ELine.EndX = 2 * Constant - ELine.EndX
  423.                     Temp.Add(ELine)
  424.                 End If
  425.             Next
  426.             Me.Items.AddRange(Temp)
  427.         ElseIf Parameter = "y" Then
  428.             Dim Line As GraphLine
  429.             Dim ELine As ExactGraphLine
  430.             Dim Temp As New List(Of GraphItemBase)
  431.             For Each GenericItem As GraphItemBase In Me.Items
  432.                 If (TypeOf GenericItem Is GraphLine) Then
  433.                     Line = CType(GenericItem, GraphLine).Clone
  434.                     Line.Position = New Point(Line.Position.X, 2 * Constant - Line.Position.Y)
  435.                     Line.EndPoint = New Point(Line.EndPoint.X, 2 * Constant - Line.Position.Y)
  436.                     Temp.Add(Line)
  437.                 ElseIf (TypeOf GenericItem Is ExactGraphLine) Then
  438.                     ELine = CType(GenericItem, ExactGraphLine).Clone
  439.                     ELine.StartY = 2 * Constant - ELine.StartY
  440.                     ELine.EndY = 2 * Constant - ELine.EndY
  441.                     Temp.Add(ELine)
  442.                 End If
  443.             Next
  444.             Me.Items.AddRange(Temp)
  445.         End If
  446.     End Sub
  447.  
  448.     Public Sub CompleteSymmetricRelation()
  449.         Dim First, Last As Point
  450.         Dim GenericItem As GraphItemBase
  451.  
  452.         If Me.Items.Count = 0 Then
  453.             Exit Sub
  454.         End If
  455.  
  456.         GenericItem = Me.Items(Me.Items.Count - 1)
  457.         If (TypeOf GenericItem Is GraphLine) Then
  458.             Dim Line As Object = GenericItem
  459.             Last = Line.EndPoint
  460.         End If
  461.  
  462.         GenericItem = Me.Items(0)
  463.         If (TypeOf GenericItem Is GraphLine) Or (TypeOf GenericItem Is ExactGraphLine) Then
  464.             Dim Line As Object = GenericItem
  465.             First = Line.Position
  466.         End If
  467.  
  468.         If First.Y > Last.Y Then
  469.             DoAxialSymmetry("y", First.Y)
  470.         Else
  471.             DoAxialSymmetry("y", Last.Y)
  472.         End If
  473.  
  474.         If First.X > Last.X Then
  475.             DoAxialSymmetry("x", Last.X)
  476.         Else
  477.             DoAxialSymmetry("x", First.X)
  478.         End If
  479.  
  480.         MyBase.Refresh()
  481.     End Sub
  482.     '---------------------------
  483.  
  484.     Private Sub GraphArea_Load(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Load
  485.         RedrawEssentialItems()
  486.         AssociatedImage = New Bitmap(Me.Width, Me.Height)
  487.         'AssociatedGraphic = Graphics.FromImage(AssociatedImage)
  488.     End Sub
  489.  
  490.     Private Sub GraphArea_Paint(ByVal sender As System.Object, ByVal e As System.Windows.Forms.PaintEventArgs) Handles MyBase.Paint
  491.         If AssociatedGraphic Is Nothing Then
  492.             AssociatedGraphic = Graphics.FromImage(AssociatedImage)
  493.         End If
  494.         AssociatedGraphic.Clear(Me.BackColor)
  495.  
  496.         For Each Item As GraphItemBase In EssentialItems
  497.             Item.Draw(e.Graphics)
  498.             Item.Draw(AssociatedGraphic)
  499.         Next
  500.  
  501.         For Each Item As GraphItemBase In Items
  502.             Try
  503.                 Item.Draw(e.Graphics)
  504.                 Item.Draw(AssociatedGraphic)
  505.             Catch Ex As Exception
  506.                 If Me.LaunchExceptionOnDrawError Then
  507.                     MessageBox.Show("Si e' verificato un errore durante le operazioni di disegno. La causa puo' essere imputata a valori troppo elevati delle coordinate dei punti, " & _
  508.                     "oppure a valori non rappresentabili, quali Infinito, -Infinito o Nessun Valore.", "MGraphing", MessageBoxButtons.OK, MessageBoxIcon.Error)
  509.                     Exit Sub
  510.                 End If
  511.             End Try
  512.         Next
  513.     End Sub
  514.  
  515.     Private Sub GraphArea_Resize(ByVal sender As Object, ByVal e As System.EventArgs) Handles Me.Resize
  516.         If AssociatedImage IsNot Nothing Then
  517.             AssociatedImage = New Bitmap(AssociatedImage, Me.Width, Me.Height)
  518.             AssociatedGraphic = Graphics.FromImage(AssociatedImage)
  519.         End If
  520.     End Sub
  521. End Class