Added source code.
This commit is contained in:
101
Source/GraphingCalculator/Controls/EvaluateWindow.xaml
Normal file
101
Source/GraphingCalculator/Controls/EvaluateWindow.xaml
Normal file
@ -0,0 +1,101 @@
|
||||
<Window x:Class="GraphingCalculator.EvaluateWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Evaluate expression" Height="251" Width="471" WindowStartupLocation="CenterScreen"
|
||||
WindowStyle="ToolWindow" SnapsToDevicePixels="True"
|
||||
KeyUp="Window_KeyUp">
|
||||
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/GroupBoxStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint=".5,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#BBB" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Window.Background>
|
||||
|
||||
<Grid Margin="3">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="5"/>
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GridSplitter Grid.Column="1" Grid.Row="0" Background="Transparent"
|
||||
VerticalAlignment="Stretch" HorizontalAlignment="Stretch"/>
|
||||
|
||||
<GroupBox Header="Input expression" Margin="0,0,-3,0">
|
||||
<TextBox Name="inputExpression" TextWrapping="Wrap"/>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Column="2" Header="Variables" Margin="-3,0,0,0">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListBox Name="listVars" Grid.ColumnSpan="100" Margin="0,0,0,2">
|
||||
<ListBox.ContextMenu>
|
||||
<ContextMenu>
|
||||
<MenuItem Header="Edit" Click="contextEdit_Click"/>
|
||||
<MenuItem Header="Delete" Click="contextDelete_Click" />
|
||||
<MenuItem Header="Clear list" Click="contextClear_Click" />
|
||||
</ContextMenu>
|
||||
</ListBox.ContextMenu>
|
||||
</ListBox>
|
||||
|
||||
<TextBlock Grid.Row="1" Grid.Column="0" VerticalAlignment="Center">Name:</TextBlock>
|
||||
<TextBox Name="inputVarName" Grid.Row="1" Grid.Column="1" />
|
||||
<TextBlock Grid.Row="1" Grid.Column="2" VerticalAlignment="Center" Margin="3,0,0,0">Value:</TextBlock>
|
||||
<TextBox Name="inputVarValue" Grid.Row="1" Grid.Column="3" />
|
||||
<Button VerticalAlignment="Center" Name="buttonAdd"
|
||||
Grid.Row="1" Grid.Column="4" Margin="3,0,0,0"
|
||||
Click="buttonAdd_Click">Add</Button>
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Grid.Row="1" Grid.ColumnSpan="3" Header="Result">
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBox Name="outputResult" Grid.ColumnSpan="2" IsReadOnly="True" Background="White"
|
||||
Margin="0,0,0,2"/>
|
||||
|
||||
<Button Name="buttonClose" Grid.Row="1" Grid.Column="1" Width="80" Margin="2"
|
||||
HorizontalAlignment="Left" Click="buttonClose_Click">Close</Button>
|
||||
<Button Name="buttonEval" Grid.Row="1" Width="80" Margin="2"
|
||||
HorizontalAlignment="Right" Click="buttonEval_Click">Evaluate</Button>
|
||||
|
||||
</Grid>
|
||||
</GroupBox>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
216
Source/GraphingCalculator/Controls/EvaluateWindow.xaml.cs
Normal file
216
Source/GraphingCalculator/Controls/EvaluateWindow.xaml.cs
Normal file
@ -0,0 +1,216 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for EvaluateWindow.xaml
|
||||
/// </summary>
|
||||
public partial class EvaluateWindow : Window
|
||||
{
|
||||
private Dictionary<string, double> variables = new Dictionary<string, double>();
|
||||
|
||||
#region Properties
|
||||
public string InputExpression
|
||||
{
|
||||
get { return inputExpression.Text; }
|
||||
set { inputExpression.Text = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public EvaluateWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
public EvaluateWindow(string txt)
|
||||
{
|
||||
InitializeComponent();
|
||||
InputExpression = txt;
|
||||
|
||||
// Convenience: evaluate already
|
||||
buttonEval_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region User input
|
||||
private void buttonAdd_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
string errorMessage = "";
|
||||
double val = 0;
|
||||
|
||||
outputResult.Clear();
|
||||
|
||||
// Verify boxes are not empty
|
||||
if (inputVarName.Text == "" || inputVarValue.Text == "")
|
||||
errorMessage = "Name or value cannot be empty!";
|
||||
|
||||
// Get number
|
||||
if (errorMessage == "" && !double.TryParse(inputVarValue.Text, out val))
|
||||
{
|
||||
try {
|
||||
Expression expr = new Expression(inputVarValue.Text);
|
||||
val = expr.Evaluate();
|
||||
}
|
||||
|
||||
catch { errorMessage = "Value must be a number!"; }
|
||||
}
|
||||
|
||||
// Verify name is unique
|
||||
if (errorMessage == "" && variables.ContainsKey(inputVarName.Text))
|
||||
{
|
||||
var res = MessageBox.Show("A variable with the same name already exists. Replace it with the new value?", "Warning", MessageBoxButton.YesNo);
|
||||
if (res != MessageBoxResult.Yes) errorMessage = "A variable with the same name already exists!";
|
||||
}
|
||||
|
||||
// Verify name doesn't contain forbidden characters
|
||||
if (errorMessage == "")
|
||||
{
|
||||
bool ok = char.IsLetter (inputVarName.Text.First());
|
||||
foreach (var i in inputVarName.Text)
|
||||
if (!char.IsLetterOrDigit(i)) ok = false;
|
||||
|
||||
if (!ok) errorMessage = "Forbidden variable name, it can only contain letters or digits!";
|
||||
}
|
||||
|
||||
// Add variable
|
||||
if (errorMessage == "")
|
||||
{
|
||||
variables[inputVarName.Text] = val;
|
||||
|
||||
// Remove if it exists already
|
||||
for (int i = 0; i < listVars.Items.Count; i++)
|
||||
{
|
||||
string str = listVars.Items[i] as string;
|
||||
if (str != null && str.StartsWith(inputVarName.Text + " = ")) listVars.Items.RemoveAt(i);
|
||||
}
|
||||
|
||||
// Add variable
|
||||
listVars.Items.Add(inputVarName.Text + " = " + inputVarValue.Text);
|
||||
|
||||
// Clear text boxes
|
||||
inputVarName.Clear();
|
||||
inputVarValue.Clear();
|
||||
}
|
||||
|
||||
else
|
||||
{
|
||||
outputResult.Foreground = Brushes.DarkRed;
|
||||
outputResult.Text = "Error adding variable: " + errorMessage;
|
||||
}
|
||||
}
|
||||
|
||||
private void buttonEval_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Create expression
|
||||
Expression expression = new Expression(inputExpression.Text);
|
||||
double result = 0;
|
||||
|
||||
// Add variables
|
||||
foreach (var i in variables)
|
||||
expression.Variables.Add(i.Key, i.Value);
|
||||
|
||||
// Try to evaluate
|
||||
try {
|
||||
result = expression.Evaluate();
|
||||
}
|
||||
|
||||
catch (Exception ex) {
|
||||
outputResult.Text = "Error evaluating: " + ex.Message;
|
||||
outputResult.Foreground = Brushes.DarkRed;
|
||||
|
||||
#region Log
|
||||
Log.LogEvent("Failed to evaluate expression '{0}'. Message: {1}", inputExpression.Text, ex.Message);
|
||||
Log.LogEvent("> Stack trace: {0}", ex.StackTrace);
|
||||
|
||||
if (listVars.Items.Count > 0) Log.LogEvent("> Variables: ");
|
||||
|
||||
foreach (var i in listVars.Items)
|
||||
Log.LogEvent(">> {0}", i.ToString());
|
||||
#endregion
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
// Output results
|
||||
outputResult.Text = Math.Round(result, 15).ToString();
|
||||
outputResult.Foreground = Brushes.Black;
|
||||
|
||||
#region Log
|
||||
// Log what happened here
|
||||
Log.LogEvent("Evaluated expression '{0}' result={1}", inputExpression.Text, outputResult.Text);
|
||||
if (listVars.Items.Count > 0) Log.LogEvent("> WHERE: ");
|
||||
|
||||
foreach (var i in listVars.Items)
|
||||
Log.LogEvent(">> {0}", i.ToString());
|
||||
#endregion
|
||||
}
|
||||
|
||||
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void contextEdit_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Make sure we have 1 selected item
|
||||
if (listVars.SelectedItems.Count != 1) return;
|
||||
|
||||
// Get key
|
||||
var item = listVars.SelectedItem as string;
|
||||
if (item == null) return;
|
||||
string key = item.Substring(0, item.IndexOf(" = "));
|
||||
|
||||
// Place in input boxes
|
||||
inputVarName.Text = key;
|
||||
inputVarValue.Text = variables[key].ToString();
|
||||
|
||||
// Remove item
|
||||
listVars.Items.Remove(listVars.SelectedItem);
|
||||
variables.Remove(key);
|
||||
}
|
||||
|
||||
private void contextDelete_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
// Make sure we have 1 selected item
|
||||
if (listVars.SelectedItems.Count != 1) return;
|
||||
|
||||
// Get key
|
||||
var item = listVars.SelectedItem as string;
|
||||
if (item == null) return;
|
||||
string key = item.Substring(0, item.IndexOf(" = "));
|
||||
|
||||
// Remove
|
||||
listVars.Items.Remove(listVars.SelectedItem);
|
||||
variables.Remove(key);
|
||||
}
|
||||
|
||||
private void contextClear_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
listVars.Items.Clear();
|
||||
variables.Clear();
|
||||
}
|
||||
|
||||
private void Window_KeyUp(object sender, KeyEventArgs e)
|
||||
{
|
||||
e.Handled = true;
|
||||
if (e.Key == Key.Escape) buttonClose_Click(this, new RoutedEventArgs());
|
||||
else if (e.Key == Key.Enter) buttonEval_Click(this, new RoutedEventArgs());
|
||||
else if (e.Key == Key.Insert) buttonAdd_Click(this, new RoutedEventArgs());
|
||||
|
||||
else e.Handled = false;
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
137
Source/GraphingCalculator/Controls/GraphingCanvas.xaml
Normal file
137
Source/GraphingCalculator/Controls/GraphingCanvas.xaml
Normal file
@ -0,0 +1,137 @@
|
||||
<Canvas x:Class="GraphingCalculator.GraphingCanvas"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
|
||||
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
|
||||
mc:Ignorable="d" d:DesignHeight="234" d:DesignWidth="348"
|
||||
ClipToBounds="True"
|
||||
SizeChanged="Canvas_SizeChanged"
|
||||
MouseWheel="Canvas_MouseWheel"
|
||||
>
|
||||
|
||||
<Canvas.Resources>
|
||||
<Style TargetType="Button">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="Button">
|
||||
<Grid Name="grid">
|
||||
<Border Name="border" CornerRadius="4" Visibility="Collapsed"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="Orange"
|
||||
BorderThickness="1">
|
||||
<Border.Background>
|
||||
<RadialGradientBrush Center=".5, .5" GradientOrigin=".5,1" RadiusX="1" RadiusY=".7">
|
||||
<GradientStop Color="#FFBF6A" Offset="0" />
|
||||
<GradientStop Color="#FFF6E2" Offset="1" />
|
||||
</RadialGradientBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
<Border Name="blackness" CornerRadius="4" Background="Brown" Opacity="0" />
|
||||
|
||||
<ContentPresenter VerticalAlignment="Center" Margin="3"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="blackness" Property="Opacity" Value=".3" />
|
||||
</Trigger>
|
||||
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
|
||||
<Style TargetType="RepeatButton">
|
||||
<Setter Property="OverridesDefaultStyle" Value="True" />
|
||||
<Setter Property="SnapsToDevicePixels" Value="True" />
|
||||
<Setter Property="Template">
|
||||
<Setter.Value>
|
||||
<ControlTemplate TargetType="RepeatButton">
|
||||
<Grid Name="grid">
|
||||
<Border Name="border" CornerRadius="4" Visibility="Collapsed"
|
||||
VerticalAlignment="Stretch"
|
||||
HorizontalAlignment="Stretch"
|
||||
BorderBrush="Orange"
|
||||
BorderThickness="1">
|
||||
<Border.Background>
|
||||
<RadialGradientBrush Center=".5, .5" GradientOrigin=".5,1" RadiusX="1" RadiusY=".7">
|
||||
<GradientStop Color="#FFBF6A" Offset="0" />
|
||||
<GradientStop Color="#FFF6E2" Offset="1" />
|
||||
</RadialGradientBrush>
|
||||
</Border.Background>
|
||||
</Border>
|
||||
|
||||
<Border Name="blackness" CornerRadius="4" Background="Brown" Opacity="0" />
|
||||
|
||||
<ContentPresenter VerticalAlignment="Center" Margin="3"
|
||||
HorizontalAlignment="Center" />
|
||||
</Grid>
|
||||
|
||||
<ControlTemplate.Triggers>
|
||||
<Trigger Property="IsMouseOver" Value="True">
|
||||
<Setter TargetName="border" Property="Visibility" Value="Visible" />
|
||||
</Trigger>
|
||||
|
||||
<Trigger Property="IsPressed" Value="True">
|
||||
<Setter TargetName="blackness" Property="Opacity" Value=".3" />
|
||||
</Trigger>
|
||||
|
||||
</ControlTemplate.Triggers>
|
||||
</ControlTemplate>
|
||||
</Setter.Value>
|
||||
</Setter>
|
||||
</Style>
|
||||
</Canvas.Resources>
|
||||
|
||||
<RepeatButton Name="buttonUp" Canvas.Right="25" Canvas.Top="5"
|
||||
Width="20" Height="20" Click="buttonUp_Click">
|
||||
<Path Height="12" Stretch="Fill" Fill="Gray"
|
||||
Data="F1 M 190.792,238.149L 182.688,252.184L 198.895,252.184L 190.792,238.149 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<RepeatButton Name="buttonLeft" Canvas.Right="45" Canvas.Top="25"
|
||||
Width="20" Height="20" Click="buttonLeft_Click" >
|
||||
<Path Width="12" Stretch="Fill" Fill="Gray" Data="F1 M 204.774,246.729L 218.809,254.833L 218.809,238.626L 204.774,246.729 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<Button Name="buttonReset"
|
||||
Canvas.Right="25" Canvas.Top="25"
|
||||
Width="20" Height="20"
|
||||
Click="buttonReset_Click"
|
||||
ToolTip="Reset" >
|
||||
<Ellipse Width="12" Height="12" Fill="Gray"/>
|
||||
</Button>
|
||||
|
||||
<RepeatButton Name="buttonRight"
|
||||
Canvas.Right="5" Canvas.Top="25"
|
||||
Width="20" Height="20" Click="buttonRight_Click" >
|
||||
<Path Width="12" Stretch="Fill" Fill="Gray" Data="F1 M 214.722,227.667L 200.686,219.563L 200.686,235.77L 214.722,227.667 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<RepeatButton Name="buttonBottom" Canvas.Right="25" Canvas.Top="45"
|
||||
Width="20" Height="20" Click="buttonBottom_Click" >
|
||||
<Path Height="12" Stretch="Fill" Fill="Gray" Data="F1 M 188.333,235.024L 196.437,220.988L 180.23,220.988L 188.333,235.024 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<!-- Zoom buttons -->
|
||||
<RepeatButton Name="buttonZoomIn" Canvas.Right="5" Canvas.Bottom="5"
|
||||
Width="25" Height="20" Click="buttonZoomIn_Click">
|
||||
<Path Width="12" Height="12" Stretch="Fill" Fill="Gray" Data="M 139.292,225.542L 147.292,225.542L 147.292,233.542L 155.292,233.542L 155.292,241.542L 147.292,241.542L 147.292,249.542L 139.292,249.542L 139.292,241.542L 131.292,241.542L 131.292,233.542L 139.292,233.542L 139.292,225.542 Z "/>
|
||||
</RepeatButton>
|
||||
|
||||
<RepeatButton Name="buttonZoomOut" Canvas.Right="30" Canvas.Bottom="5"
|
||||
Width="25" Height="20" Click="buttonZoomOut_Click">
|
||||
<Rectangle Width="12" Height="4.32" Stretch="Fill" Fill="Gray"/>
|
||||
</RepeatButton>
|
||||
|
||||
</Canvas>
|
466
Source/GraphingCalculator/Controls/GraphingCanvas.xaml.cs
Normal file
466
Source/GraphingCalculator/Controls/GraphingCanvas.xaml.cs
Normal file
@ -0,0 +1,466 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Navigation;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for GraphingCanvas.xaml
|
||||
/// </summary>
|
||||
public partial class GraphingCanvas : Canvas
|
||||
{
|
||||
#region Settings
|
||||
private double PlotPrecision
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.PlotPrecision; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.PlotPrecision = value; }
|
||||
}
|
||||
|
||||
private double GridDensity
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.GridDensity; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.GridDensity = value; }
|
||||
}
|
||||
|
||||
private int RoundDoublesGraph
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph = value; }
|
||||
}
|
||||
|
||||
private double NavigationSens
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.NavigationSensitivity; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.NavigationSensitivity = value; }
|
||||
}
|
||||
|
||||
private double ZoomSens
|
||||
{
|
||||
get { return GraphingCalculator.Properties.Settings.Default.ZoomSensitivity; }
|
||||
set { GraphingCalculator.Properties.Settings.Default.ZoomSensitivity = value; }
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
#region Constants
|
||||
private Point specialSeparator = new Point(double.MaxValue, double.MaxValue);
|
||||
private Point specialVisibleTrue = new Point(0, double.MaxValue);
|
||||
private Point specialVisibleFalse = new Point(0, double.MinValue);
|
||||
#endregion
|
||||
|
||||
#region Expressions
|
||||
private List<VisualExpression> expressions = new List<VisualExpression>();
|
||||
public List<VisualExpression> Expressions { get { return expressions; } }
|
||||
|
||||
/// <summary>
|
||||
/// Adds an expression to be plotted
|
||||
/// </summary>
|
||||
public void AddExpression(VisualExpression ex)
|
||||
{
|
||||
this.Expressions.Add(ex);
|
||||
EvaluateExpression(ex);
|
||||
Redraw();
|
||||
|
||||
#region Log
|
||||
Log.LogEvent("Plotted expression '{0}'", ex.ExpressionString);
|
||||
#endregion
|
||||
}
|
||||
|
||||
public void SetExpressionVisibility(int index, bool visibility)
|
||||
{
|
||||
if (Expressions[index].IsVisible == visibility) return;
|
||||
|
||||
if (queuedPoints.Count != 0) {
|
||||
int i, ci;
|
||||
for (i = 0, ci = -1; i < queuedPoints.Count && ci < index; i++)
|
||||
if (queuedPoints[i] == specialSeparator) ci++;
|
||||
|
||||
queuedPoints[i] = (visibility) ? specialVisibleTrue : specialVisibleFalse;
|
||||
}
|
||||
|
||||
Expressions[index].IsVisible = visibility;
|
||||
Redraw();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Canvas and screen bounds
|
||||
public Bounds CanvasBounds { get; set; }
|
||||
public Bounds ScreenBounds { get; set; }
|
||||
|
||||
public double CoordXToCanvas(double x)
|
||||
{
|
||||
double scrX = x - ScreenBounds.Left;
|
||||
return CanvasBounds.Left + (CanvasBounds.Width * (scrX / ScreenBounds.Width));
|
||||
}
|
||||
|
||||
public double CoordXToScreen(double x)
|
||||
{
|
||||
double canX = x - CanvasBounds.Left;
|
||||
return ScreenBounds.Left + (ScreenBounds.Width * (canX / CanvasBounds.Width));
|
||||
}
|
||||
|
||||
public double CoordYToCanvas(double y)
|
||||
{
|
||||
double scrY = y - ScreenBounds.Bottom;
|
||||
return CanvasBounds.Bottom + (CanvasBounds.Height * (scrY / ScreenBounds.Height));
|
||||
}
|
||||
|
||||
public double CoordYToScreen(double y)
|
||||
{
|
||||
double canY = y - CanvasBounds.Bottom;
|
||||
return ScreenBounds.Bottom + (ScreenBounds.Height * (canY / CanvasBounds.Height));
|
||||
}
|
||||
|
||||
public Point CoordToCanvas(double x, double y)
|
||||
{
|
||||
return new Point(CoordXToCanvas(x), CoordYToCanvas(y));
|
||||
}
|
||||
|
||||
public Point CoordToCanvas(Point p)
|
||||
{
|
||||
return new Point(CoordXToCanvas(p.X), CoordYToCanvas(p.Y));
|
||||
}
|
||||
|
||||
public Point CoordToScreen(double x, double y)
|
||||
{
|
||||
return new Point(CoordXToScreen(x), CoordYToScreen(y));
|
||||
}
|
||||
|
||||
public Point CoordToScreen(Point p)
|
||||
{
|
||||
return new Point(CoordXToScreen(p.X), CoordYToScreen(p.Y));
|
||||
}
|
||||
|
||||
public void SetCanvasBounds(Bounds b)
|
||||
{
|
||||
if (b.Width <= 0 || b.Height <= 0) return;
|
||||
|
||||
CanvasBounds.Top = b.Top;
|
||||
CanvasBounds.Bottom = b.Bottom;
|
||||
CanvasBounds.Left = b.Left;
|
||||
CanvasBounds.Right = b.Right;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructor
|
||||
public GraphingCanvas()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
CanvasBounds = new Bounds(-5, 5, 5, -5);
|
||||
ScreenBounds = new Bounds(0, 0, this.ActualWidth, this.ActualHeight);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region UI Events
|
||||
private void Canvas_SizeChanged(object sender, SizeChangedEventArgs e)
|
||||
{
|
||||
ScreenBounds.Right = e.NewSize.Width;
|
||||
ScreenBounds.Bottom = e.NewSize.Height;
|
||||
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonReset_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
CanvasBounds.Left = -5;
|
||||
CanvasBounds.Right = 5;
|
||||
CanvasBounds.Bottom = -5;
|
||||
CanvasBounds.Top = 5;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonUp_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double h = CanvasBounds.Height * NavigationSens;
|
||||
CanvasBounds.Top += h;
|
||||
CanvasBounds.Bottom += h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonLeft_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double w = CanvasBounds.Width * NavigationSens;
|
||||
CanvasBounds.Left -= w;
|
||||
CanvasBounds.Right -= w;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonRight_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double w = CanvasBounds.Width * NavigationSens;
|
||||
CanvasBounds.Left += w;
|
||||
CanvasBounds.Right += w;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonBottom_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double h = CanvasBounds.Height * NavigationSens;
|
||||
CanvasBounds.Top -= h;
|
||||
CanvasBounds.Bottom -= h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonZoomIn_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double new_w = CanvasBounds.Width / ZoomSens;
|
||||
double new_h = CanvasBounds.Height / ZoomSens;
|
||||
double diff_w = (CanvasBounds.Width - new_w) / 2 ;
|
||||
double diff_h = (CanvasBounds.Height - new_h) / 2;
|
||||
|
||||
CanvasBounds.Left += diff_w;
|
||||
CanvasBounds.Right -= diff_w;
|
||||
CanvasBounds.Bottom += diff_h;
|
||||
CanvasBounds.Top -= diff_h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
|
||||
private void buttonZoomOut_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double new_w = CanvasBounds.Width * ZoomSens;
|
||||
double new_h = CanvasBounds.Height * ZoomSens;
|
||||
double diff_w = (CanvasBounds.Width - new_w) / 2;
|
||||
double diff_h = (CanvasBounds.Height - new_h) / 2;
|
||||
|
||||
CanvasBounds.Left += diff_w;
|
||||
CanvasBounds.Right -= diff_w;
|
||||
CanvasBounds.Bottom += diff_h;
|
||||
CanvasBounds.Top -= diff_h;
|
||||
|
||||
EvaluateExpressions();
|
||||
Redraw();
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Expression evaluation
|
||||
List<Point> queuedPoints = new List<Point>();
|
||||
|
||||
public void EvaluateExpression(VisualExpression expr)
|
||||
{
|
||||
queuedPoints.Add(specialSeparator);
|
||||
queuedPoints.Add((expr.IsVisible) ? specialVisibleTrue : specialVisibleFalse);
|
||||
|
||||
for (double x = CanvasBounds.Left; x <= CanvasBounds.Right; x += CanvasBounds.Width / PlotPrecision)
|
||||
{
|
||||
expr.Variables["x"] = expr.Variables["X"] = x;
|
||||
queuedPoints.Add(new Point(x, expr.Evaluate()));
|
||||
}
|
||||
}
|
||||
|
||||
public void EvaluateExpressions()
|
||||
{
|
||||
queuedPoints.Clear();
|
||||
foreach (var expr in Expressions)
|
||||
EvaluateExpression(expr);
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Rendering
|
||||
public void Redraw()
|
||||
{
|
||||
this.InvalidateVisual();
|
||||
}
|
||||
|
||||
private void RenderDouble(DrawingContext dc, double n, Point pos, bool center)
|
||||
{
|
||||
FormattedText text = new FormattedText(Math.Round(n, RoundDoublesGraph).ToString(),
|
||||
new System.Globalization.CultureInfo("en-US"), FlowDirection.LeftToRight,
|
||||
new Typeface("Arial"), 8.0, Brushes.Black);
|
||||
|
||||
if (center) dc.DrawText(text, new Point(pos.X - (text.Width / 2), pos.Y + 10));
|
||||
else dc.DrawText(text, new Point(pos.X + 2, pos.Y));
|
||||
}
|
||||
|
||||
private void RenderGridVertical(DrawingContext dc, Pen pen, double from, double to, double interv)
|
||||
{
|
||||
if (from > to) interv *= -1;
|
||||
|
||||
// Draw vertical grid
|
||||
for (double i = from; (from < to && i < to) || (from > to && i > to); i += interv)
|
||||
{
|
||||
Point text = CoordToScreen(i, 0);
|
||||
Point f = CoordToScreen(i, CanvasBounds.Bottom);
|
||||
Point t = CoordToScreen(i, CanvasBounds.Top);
|
||||
|
||||
dc.DrawLine(pen, f, t);
|
||||
RenderDouble(dc, i, text, true);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderGridHorizontal(DrawingContext dc, Pen pen, double from, double to, double interv)
|
||||
{
|
||||
if (from > to) interv *= -1;
|
||||
|
||||
// Draw vertical grid
|
||||
for (double i = from; (from < to && i < to) || (from > to && i > to); i += interv)
|
||||
{
|
||||
Point text = CoordToScreen(0, i);
|
||||
Point f = CoordToScreen(CanvasBounds.Left, i);
|
||||
Point t = CoordToScreen(CanvasBounds.Right, i);
|
||||
|
||||
dc.DrawLine(pen, f, t);
|
||||
RenderDouble(dc, i, text, false);
|
||||
}
|
||||
}
|
||||
|
||||
private void RenderGrid(DrawingContext dc)
|
||||
{
|
||||
Pen pen = new Pen(new SolidColorBrush(Color.FromRgb(0xa6, 0xdd, 0xe2)), 1);
|
||||
pen.DashStyle = DashStyles.Dash;
|
||||
|
||||
double w_div = Math.Truncate(this.ActualWidth / GridDensity);
|
||||
double h_div = Math.Truncate(this.ActualHeight / GridDensity);
|
||||
if (Convert.ToInt32(w_div) % 2 == 1) w_div += 1;
|
||||
if (Convert.ToInt32(h_div) % 2 == 1) h_div += 1;
|
||||
|
||||
double w_int = CanvasBounds.Width / w_div;
|
||||
double h_int = CanvasBounds.Height / h_div;
|
||||
|
||||
RenderGridVertical(dc, pen, 0, CanvasBounds.Right, w_int);
|
||||
RenderGridVertical(dc, pen, 0, CanvasBounds.Left, w_int);
|
||||
RenderGridHorizontal(dc, pen, 0, CanvasBounds.Top, h_int);
|
||||
RenderGridHorizontal(dc, pen, 0, CanvasBounds.Bottom, h_int);
|
||||
}
|
||||
|
||||
private void RenderAxis(DrawingContext dc)
|
||||
{
|
||||
Point dst;
|
||||
Pen lines = new Pen(Brushes.Coral, 1.5);
|
||||
|
||||
// Draw X axis
|
||||
dst = CoordToScreen(CanvasBounds.Right, 0);
|
||||
dc.DrawLine(lines, CoordToScreen(CanvasBounds.Left, 0), dst);
|
||||
dc.DrawLine(lines, dst, new Point(dst.X - 5, dst.Y + 2));
|
||||
dc.DrawLine(lines, dst, new Point(dst.X - 5, dst.Y - 2));
|
||||
|
||||
// Draw Y axis
|
||||
dst = CoordToScreen(0, CanvasBounds.Top);
|
||||
dc.DrawLine(lines, CoordToScreen(0, CanvasBounds.Bottom), dst);
|
||||
dc.DrawLine(lines, dst, new Point(dst.X - 2, dst.Y + 5));
|
||||
dc.DrawLine(lines, dst, new Point(dst.X + 2, dst.Y + 5));
|
||||
}
|
||||
|
||||
private void RenderFunctions(DrawingContext dc)
|
||||
{
|
||||
if (Expressions.Count == 0) return;
|
||||
|
||||
int exprIndex = -1;
|
||||
bool visible = true;
|
||||
Pen pen = new Pen();
|
||||
|
||||
for (int i = 0; i < queuedPoints.Count - 1; i++)
|
||||
{
|
||||
if (queuedPoints[i] == specialSeparator)
|
||||
{
|
||||
exprIndex++; i++;
|
||||
pen = new Pen(new SolidColorBrush(Expressions[exprIndex].Color), Expressions[exprIndex].Thickness);
|
||||
visible = (queuedPoints[i] == specialVisibleTrue);
|
||||
}
|
||||
|
||||
else if (visible && queuedPoints[i + 1] != specialSeparator)
|
||||
{
|
||||
Point src = CoordToScreen(queuedPoints[i]);
|
||||
Point dst = CoordToScreen(queuedPoints[i + 1]);
|
||||
|
||||
if (ScreenBounds.IsInBounds(src) || ScreenBounds.IsInBounds(dst))
|
||||
dc.DrawLine(pen, src, dst);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
protected override void OnRender(DrawingContext dc)
|
||||
{
|
||||
// Reduce garbage collector intrusions
|
||||
var latency = System.Runtime.GCSettings.LatencyMode;
|
||||
System.Runtime.GCSettings.LatencyMode = System.Runtime.GCLatencyMode.LowLatency;
|
||||
|
||||
// Draw grid
|
||||
RenderGrid(dc);
|
||||
RenderAxis(dc);
|
||||
|
||||
// Render functions
|
||||
RenderFunctions(dc);
|
||||
|
||||
// Base render
|
||||
base.OnRender(dc);
|
||||
|
||||
// Restore previous garbage collector setting
|
||||
System.Runtime.GCSettings.LatencyMode = latency;
|
||||
}
|
||||
#endregion
|
||||
|
||||
private void Canvas_MouseWheel(object sender, MouseWheelEventArgs e)
|
||||
{
|
||||
if (e.Delta > 0) buttonZoomIn_Click(this, new RoutedEventArgs());
|
||||
else buttonZoomOut_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
#region Navigation control
|
||||
public void PeformMouseWheelChange(MouseWheelEventArgs e)
|
||||
{
|
||||
Canvas_MouseWheel(this, e);
|
||||
}
|
||||
|
||||
public void PerformMoveLeft()
|
||||
{
|
||||
buttonLeft_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformMoveRight()
|
||||
{
|
||||
buttonRight_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformMoveUp()
|
||||
{
|
||||
buttonUp_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformMoveDown()
|
||||
{
|
||||
buttonBottom_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformReset()
|
||||
{
|
||||
buttonReset_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformZoomIn()
|
||||
{
|
||||
buttonZoomIn_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
public void PerformZoomOut()
|
||||
{
|
||||
buttonZoomOut_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
80
Source/GraphingCalculator/Controls/IntegralWindow.xaml
Normal file
80
Source/GraphingCalculator/Controls/IntegralWindow.xaml
Normal file
@ -0,0 +1,80 @@
|
||||
<Window x:Class="GraphingCalculator.Controls.IntegralWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Integral" Height="331" Width="261" WindowStyle="ToolWindow" WindowStartupLocation="CenterScreen">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/RadioButtonStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/GroupBoxStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/WarningGroupBoxStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint=".5,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#999" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Window.Background>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<GroupBox Style="{StaticResource WarningGroupBox}"
|
||||
Grid.Row="0" Grid.ColumnSpan="2" Margin="8,5,8,2"
|
||||
HorizontalContentAlignment="Stretch"
|
||||
Header="Warning" TextBlock.TextAlignment="Center" >
|
||||
<TextBlock TextWrapping="Wrap">This feature is experimental, so the given results may not fully be accurate.</TextBlock>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Expression" Grid.Row="1">
|
||||
<TextBox Name="inputExpression" TextWrapping="Wrap" />
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Interval" Grid.Row="2">
|
||||
<StackPanel>
|
||||
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="32" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="5" />
|
||||
<ColumnDefinition Width="32" />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock Grid.Column="0" VerticalAlignment="Center">From:</TextBlock>
|
||||
<TextBox Name="inputIntervalBeg" Grid.Column="1" VerticalAlignment="Center">-1</TextBox>
|
||||
<TextBlock Grid.Column="3" VerticalAlignment="Center">To:</TextBlock>
|
||||
<TextBox Name="inputIntervalEnd" Grid.Column="4" VerticalAlignment="Center">1</TextBox>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Result" Grid.Row="3">
|
||||
<TextBox Name="outputResult" IsReadOnly="True" Background="White"/>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Grid.Row="4">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Name="buttonCalculate" Grid.Column="0" HorizontalAlignment="Right" Width="80" Click="buttonCalculate_Click">Calculate</Button>
|
||||
<Button Name="buttonClose" Grid.Column="1" HorizontalAlignment="Left" Width="80" Click="buttonClose_Click">Close</Button>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
|
||||
</Window>
|
93
Source/GraphingCalculator/Controls/IntegralWindow.xaml.cs
Normal file
93
Source/GraphingCalculator/Controls/IntegralWindow.xaml.cs
Normal file
@ -0,0 +1,93 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace GraphingCalculator.Controls
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for LimitWindow.xaml
|
||||
/// </summary>
|
||||
public partial class IntegralWindow : Window
|
||||
{
|
||||
#region Properties
|
||||
public string ExpressionString
|
||||
{
|
||||
get { return inputExpression.Text; }
|
||||
set { inputExpression.Text = value; }
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Constructors
|
||||
public IntegralWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
ExpressionString = "";
|
||||
}
|
||||
|
||||
public IntegralWindow(string expression)
|
||||
{
|
||||
InitializeComponent();
|
||||
ExpressionString = expression;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Other routines
|
||||
private void Result (string result, bool error = false)
|
||||
{
|
||||
outputResult.Text = result;
|
||||
if (error) outputResult.Foreground = Brushes.DarkRed;
|
||||
else outputResult.Foreground = Brushes.Black;
|
||||
}
|
||||
#endregion
|
||||
|
||||
#region Button handlers
|
||||
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonCalculate_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
double val_beg, val_end, integr_res;
|
||||
Expression beg, end, expr;
|
||||
beg = new Expression(inputIntervalBeg.Text);
|
||||
end = new Expression(inputIntervalEnd.Text);
|
||||
expr = new Expression(inputExpression.Text);
|
||||
|
||||
// Try to evaluate interval ends
|
||||
try { val_beg = beg.Evaluate(); }
|
||||
catch { Result("Failed to evaluate interval start.", true); return; }
|
||||
|
||||
try { val_end = end.Evaluate(); }
|
||||
catch { Result("Failed to evaluate interval end.", true); return; }
|
||||
|
||||
// Try to calculate the integral
|
||||
try { integr_res = Integrator.Integrate(expr, val_beg, val_end, "x"); }
|
||||
catch (Exception ex)
|
||||
{
|
||||
Result("Failed to evaluate expression. Message: " + ex.Message, true);
|
||||
Log.LogEvent("Failed to integrate expression: {0}", expr.ExpressionString);
|
||||
Log.LogEvent("> Interval: [{0}, {1}] = [{2}, {3}]", beg.ExpressionString, end.ExpressionString, val_beg, val_end);
|
||||
Log.LogEvent("> Message: {0}", ex.Message);
|
||||
Log.LogEvent("> Stack trace: {0}", ex.StackTrace);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show result
|
||||
Result(Math.Round(integr_res, 14).ToString());
|
||||
Log.LogEvent("Integrated expression: {0}", expr.ExpressionString);
|
||||
Log.LogEvent("> Interval: [{0}, {1}] = [{2}, {3}]", beg.ExpressionString, end.ExpressionString, val_beg, val_end);
|
||||
Log.LogEvent("> Result: {0}", integr_res);
|
||||
}
|
||||
#endregion
|
||||
}
|
||||
}
|
44
Source/GraphingCalculator/Controls/LogWindow.xaml
Normal file
44
Source/GraphingCalculator/Controls/LogWindow.xaml
Normal file
@ -0,0 +1,44 @@
|
||||
<Window x:Class="GraphingCalculator.LogWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Log" Height="379" Width="543" WindowStartupLocation="CenterScreen" ShowInTaskbar="True">
|
||||
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Grid>
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<ListBox Name="listEntries" Grid.Row="0" Grid.ColumnSpan="10"
|
||||
ScrollViewer.HorizontalScrollBarVisibility="Disabled" >
|
||||
<ListBox.ItemTemplate>
|
||||
<DataTemplate>
|
||||
<TextBlock TextWrapping="Wrap" Text="{Binding}" />
|
||||
</DataTemplate>
|
||||
</ListBox.ItemTemplate>
|
||||
</ListBox>
|
||||
|
||||
<Button Name="buttonCopy" Grid.Row="1" Grid.Column="1" Width="60" Click="buttonCopy_Click">Copy</Button>
|
||||
<Button Name="buttonSave" Grid.Row="1" Grid.Column="2" Width="60" Click="buttonSave_Click">Save...</Button>
|
||||
<Button Name="buttonClear" Grid.Row="1" Grid.Column="3" Width="60" Click="buttonClear_Click">Clear</Button>
|
||||
<Button Name="buttonRefresh" Grid.Row="1" Grid.Column="0" Width="60" Click="buttonRefresh_Click">Refresh</Button>
|
||||
<Button Name="buttonClose" Grid.Row="1" Grid.Column="5" Width="60" Click="buttonClose_Click">Close</Button>
|
||||
</Grid>
|
||||
</Window>
|
74
Source/GraphingCalculator/Controls/LogWindow.xaml.cs
Normal file
74
Source/GraphingCalculator/Controls/LogWindow.xaml.cs
Normal file
@ -0,0 +1,74 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for LogWindow.xaml
|
||||
/// </summary>
|
||||
public partial class LogWindow : Window
|
||||
{
|
||||
public LogWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
buttonRefresh_Click(this, new RoutedEventArgs());
|
||||
}
|
||||
|
||||
private void buttonCopy_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
if (listEntries.SelectedIndex != -1)
|
||||
Clipboard.SetText(listEntries.SelectedItem.ToString());
|
||||
}
|
||||
|
||||
private void buttonClear_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
listEntries.Items.Clear();
|
||||
Log.Entries.Clear();
|
||||
}
|
||||
|
||||
private void buttonRefresh_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
listEntries.Items.Clear();
|
||||
|
||||
foreach (var i in Log.Entries)
|
||||
listEntries.Items.Add(i);
|
||||
}
|
||||
|
||||
private void buttonClose_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonSave_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Microsoft.Win32.SaveFileDialog dialog = new Microsoft.Win32.SaveFileDialog();
|
||||
dialog.Title = "Save log...";
|
||||
dialog.Filter = "Text file|*.txt|Log file|*.log|All files|*.*";
|
||||
|
||||
bool? res = dialog.ShowDialog();
|
||||
if (!res.HasValue && !res.Value) return;
|
||||
|
||||
try
|
||||
{
|
||||
System.IO.File.WriteAllLines(dialog.FileName, Log.Entries.ToArray());
|
||||
}
|
||||
|
||||
catch (Exception ex)
|
||||
{
|
||||
Log.LogEvent("Failed to save log to file {0}: {1}", dialog.FileName, ex.Message);
|
||||
MessageBox.Show("Error: " + ex.Message, "Failed to save log file!");
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
165
Source/GraphingCalculator/Controls/SettingsWindow.xaml
Normal file
165
Source/GraphingCalculator/Controls/SettingsWindow.xaml
Normal file
@ -0,0 +1,165 @@
|
||||
<Window x:Class="GraphingCalculator.SettingsWindow"
|
||||
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
|
||||
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
|
||||
Title="Settings" Height="320" Width="562"
|
||||
ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
|
||||
WindowStyle="ToolWindow">
|
||||
<Window.Resources>
|
||||
<ResourceDictionary>
|
||||
<ResourceDictionary.MergedDictionaries>
|
||||
<ResourceDictionary Source="/Styles/GroupBoxStyle.xaml" />
|
||||
<ResourceDictionary Source="/Styles/ButtonStyle.xaml" />
|
||||
</ResourceDictionary.MergedDictionaries>
|
||||
</ResourceDictionary>
|
||||
</Window.Resources>
|
||||
|
||||
<Window.Background>
|
||||
<LinearGradientBrush StartPoint="0,0" EndPoint=".5,1">
|
||||
<GradientStop Color="#EEE" Offset="0" />
|
||||
<GradientStop Color="#BBB" Offset="1" />
|
||||
</LinearGradientBrush>
|
||||
</Window.Background>
|
||||
|
||||
<Grid Margin="2">
|
||||
<Grid.RowDefinitions>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto"/>
|
||||
<RowDefinition Height="Auto" />
|
||||
<RowDefinition />
|
||||
<RowDefinition Height="Auto" />
|
||||
</Grid.RowDefinitions>
|
||||
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<GroupBox Header="Graph precision" Grid.Row="0">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderGraphPrecision"
|
||||
Minimum="50" Maximum="2000" TickFrequency="150"
|
||||
SmallChange="10" LargeChange="50"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>Minimum</TextBlock>
|
||||
<TextBlock Grid.Column="2">Maximum</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" FontSize="11"
|
||||
Foreground="#444" Margin="2,4,2,2">
|
||||
A higher precision means that drawing takes longer to render, making the application slower.</TextBlock>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Grid density" Grid.Column="1" Grid.Row="0">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderGridDensity"
|
||||
Minimum="10" Maximum="100" TickFrequency="5"
|
||||
SmallChange="2" LargeChange="5"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>Higher</TextBlock>
|
||||
<TextBlock Grid.Column="2">Lower</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" FontSize="11"
|
||||
Foreground="#444" Margin="2,4,2,2">
|
||||
A higher density means that more grid lines are drawn.</TextBlock>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Grid numbers precision" Grid.Row="2" Grid.RowSpan="2">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderDoublePrecision"
|
||||
Minimum="0" Maximum="15" TickFrequency="1"
|
||||
SmallChange="1" LargeChange="1" ValueChanged="sliderDoublePrecision_ValueChanged"
|
||||
TickPlacement="BottomRight" IsSnapToTickEnabled="True"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>0</TextBlock>
|
||||
<TextBlock Name="outputDoublePrecision" Grid.Column="1" HorizontalAlignment="Center">? decimals</TextBlock>
|
||||
<TextBlock Grid.Column="2">15</TextBlock>
|
||||
</Grid>
|
||||
|
||||
<TextBlock TextWrapping="Wrap" FontSize="11"
|
||||
Foreground="#444" Margin="2,4,2,2">
|
||||
A higher precision means that more decimals appear in the graph. If the value is too high, values may overlap each other.</TextBlock>
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Navigation sensitivity"
|
||||
Grid.Column="1" Grid.Row="2">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderNavigationSensitivity"
|
||||
Minimum=".01" Maximum="1.5" TickFrequency=".1"
|
||||
SmallChange=".01" LargeChange=".05" ValueChanged="sliderNavigationSensitivity_ValueChanged"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>1%</TextBlock>
|
||||
<TextBlock Name="outputNavigationSensitivity" Grid.Column="1" HorizontalAlignment="Center">?% of screen</TextBlock>
|
||||
<TextBlock Grid.Column="2">150%</TextBlock>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<GroupBox Header="Zoom sensitivity"
|
||||
Grid.Column="1" Grid.Row="3">
|
||||
<StackPanel>
|
||||
<Slider Name="sliderZoomSensitivity"
|
||||
Minimum="1.01" Maximum="2.5" TickFrequency=".1"
|
||||
SmallChange=".01" LargeChange=".05" ValueChanged="sliderZoomSensitivity_ValueChanged"
|
||||
TickPlacement="BottomRight"/>
|
||||
<Grid>
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto"/>
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<TextBlock>1%</TextBlock>
|
||||
<TextBlock Name="outputZoomSensitivity" Grid.Column="1" HorizontalAlignment="Center">?% of screen</TextBlock>
|
||||
<TextBlock Grid.Column="2">150%</TextBlock>
|
||||
</Grid>
|
||||
|
||||
</StackPanel>
|
||||
</GroupBox>
|
||||
|
||||
<Grid Grid.Row="5" Grid.ColumnSpan="2">
|
||||
<Grid.ColumnDefinitions>
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
<ColumnDefinition Width="Auto" />
|
||||
</Grid.ColumnDefinitions>
|
||||
|
||||
<Button Name="buttonDefaults" Width="80" Click="buttonDefaults_Click">Defaults</Button>
|
||||
<Button Name="buttonCancel" Width="80" Grid.Column="2" Click="buttonCancel_Click">Cancel</Button>
|
||||
<Button Name="buttonAccept" Width="80" Grid.Column="3" Click="buttonAccept_Click">Accept</Button>
|
||||
</Grid>
|
||||
|
||||
</Grid>
|
||||
</Window>
|
94
Source/GraphingCalculator/Controls/SettingsWindow.xaml.cs
Normal file
94
Source/GraphingCalculator/Controls/SettingsWindow.xaml.cs
Normal file
@ -0,0 +1,94 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.Linq;
|
||||
using System.Text;
|
||||
using System.Windows;
|
||||
using System.Windows.Controls;
|
||||
using System.Windows.Data;
|
||||
using System.Windows.Documents;
|
||||
using System.Windows.Input;
|
||||
using System.Windows.Media;
|
||||
using System.Windows.Media.Imaging;
|
||||
using System.Windows.Shapes;
|
||||
|
||||
namespace GraphingCalculator
|
||||
{
|
||||
/// <summary>
|
||||
/// Interaction logic for SettingsWindow.xaml
|
||||
/// </summary>
|
||||
public partial class SettingsWindow : Window
|
||||
{
|
||||
|
||||
public SettingsWindow()
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
this.Loaded += new RoutedEventHandler(SettingsWindow_Loaded);
|
||||
|
||||
}
|
||||
|
||||
void SettingsWindow_Loaded(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Update();
|
||||
}
|
||||
|
||||
private void Update()
|
||||
{
|
||||
sliderGraphPrecision.Value = GraphingCalculator.Properties.Settings.Default.PlotPrecision;
|
||||
sliderGridDensity.Value = GraphingCalculator.Properties.Settings.Default.GridDensity;
|
||||
sliderDoublePrecision.Value = GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph;
|
||||
sliderNavigationSensitivity.Value = GraphingCalculator.Properties.Settings.Default.NavigationSensitivity;
|
||||
sliderZoomSensitivity.Value = GraphingCalculator.Properties.Settings.Default.ZoomSensitivity;
|
||||
}
|
||||
|
||||
private void Save()
|
||||
{
|
||||
GraphingCalculator.Properties.Settings.Default.PlotPrecision = sliderGraphPrecision.Value;
|
||||
GraphingCalculator.Properties.Settings.Default.GridDensity = sliderGridDensity.Value;
|
||||
GraphingCalculator.Properties.Settings.Default.RoundDoublesGraph = Convert.ToInt32(sliderDoublePrecision.Value);
|
||||
GraphingCalculator.Properties.Settings.Default.NavigationSensitivity = sliderNavigationSensitivity.Value;
|
||||
GraphingCalculator.Properties.Settings.Default.ZoomSensitivity = sliderZoomSensitivity.Value;
|
||||
}
|
||||
|
||||
|
||||
private void buttonDefaults_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
sliderGraphPrecision.Value = 600;
|
||||
sliderGridDensity.Value = 41;
|
||||
sliderDoublePrecision.Value = 4;
|
||||
sliderNavigationSensitivity.Value = 0.1;
|
||||
sliderZoomSensitivity.Value = 1.075;
|
||||
}
|
||||
|
||||
private void buttonCancel_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
this.Close();
|
||||
}
|
||||
|
||||
private void buttonAccept_Click(object sender, RoutedEventArgs e)
|
||||
{
|
||||
Save();
|
||||
this.Close();
|
||||
}
|
||||
|
||||
|
||||
private void sliderDoublePrecision_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (outputDoublePrecision != null)
|
||||
outputDoublePrecision.Text = e.NewValue.ToString() + " decimals";
|
||||
}
|
||||
|
||||
private void sliderNavigationSensitivity_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (outputNavigationSensitivity != null)
|
||||
outputNavigationSensitivity.Text = Math.Round(e.NewValue * 100, 0).ToString() + "% of screen";
|
||||
}
|
||||
|
||||
private void sliderZoomSensitivity_ValueChanged(object sender, RoutedPropertyChangedEventArgs<double> e)
|
||||
{
|
||||
if (outputZoomSensitivity != null)
|
||||
outputZoomSensitivity.Text = Math.Round((e.NewValue-1) * 100, 0).ToString() + "% of screen";
|
||||
}
|
||||
|
||||
}
|
||||
}
|
Reference in New Issue
Block a user