Version 1.1 is out. #1
@ -12,9 +12,9 @@
|
||||
<GeneratePackageOnBuild>True</GeneratePackageOnBuild>
|
||||
<PackageId>ThatOneNerd.Graphing</PackageId>
|
||||
<Title>ThatOneNerd.Graphing</Title>
|
||||
<Version>1.0.0</Version>
|
||||
<Version>1.1.0</Version>
|
||||
<Authors>That_One_Nerd</Authors>
|
||||
<Description>A fairly adept graphing calculator made in Windows Forms. </Description>
|
||||
<Description>A fairly adept graphing calculator made in Windows Forms.</Description>
|
||||
<Copyright>MIT</Copyright>
|
||||
<RepositoryUrl>https://github.com/That-One-Nerd/Graphing</RepositoryUrl>
|
||||
<PackageReadmeFile>README.md</PackageReadmeFile>
|
||||
@ -22,6 +22,8 @@
|
||||
<PackageLicenseExpression>MIT</PackageLicenseExpression>
|
||||
<IncludeSymbols>True</IncludeSymbols>
|
||||
<SymbolPackageFormat>snupkg</SymbolPackageFormat>
|
||||
<PackageReleaseNotes>View the GitHub release for the changelog:
|
||||
https://github.com/That-One-Nerd/Graphing/releases/tag/1.1.0</PackageReleaseNotes>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
|
||||
@ -1,6 +1,12 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<PropertyGroup>
|
||||
<_LastSelectedProfileId>C:\Users\kyley\Desktop\Coding\C#\Graphing\Base\Properties\PublishProfiles\FolderProfile.pubxml</_LastSelectedProfileId>
|
||||
</PropertyGroup>
|
||||
<ItemGroup>
|
||||
<Compile Update="Forms\Controls\PieChart.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\GraphColorPickerForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@ -10,5 +16,8 @@
|
||||
<Compile Update="Forms\SetZoomForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\ViewCacheForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
32
Base/Extensions/FormattingExtensions.cs
Normal file
32
Base/Extensions/FormattingExtensions.cs
Normal file
@ -0,0 +1,32 @@
|
||||
namespace Graphing.Extensions;
|
||||
|
||||
public static class FormattingExtensions
|
||||
{
|
||||
private static readonly string[] sizeUnits =
|
||||
[
|
||||
" bytes",
|
||||
" KB",
|
||||
" MB",
|
||||
" GB",
|
||||
" TB",
|
||||
" PB",
|
||||
];
|
||||
|
||||
public static string FormatAsBytes(this long bytes)
|
||||
{
|
||||
double val = bytes;
|
||||
int unitIndex = 0;
|
||||
|
||||
while (val > 1024)
|
||||
{
|
||||
unitIndex++;
|
||||
val /= 1024;
|
||||
}
|
||||
|
||||
string result;
|
||||
if (unitIndex == 0) result = val.ToString("0");
|
||||
else result = val.ToString("0.00");
|
||||
|
||||
return result + sizeUnits[unitIndex];
|
||||
}
|
||||
}
|
||||
44
Base/Forms/Controls/PieChart.Designer.cs
generated
Normal file
44
Base/Forms/Controls/PieChart.Designer.cs
generated
Normal file
@ -0,0 +1,44 @@
|
||||
namespace Graphing.Forms.Controls
|
||||
{
|
||||
partial class PieChart
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Component Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
SuspendLayout();
|
||||
//
|
||||
// PieChart
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(13F, 32F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
Name = "PieChart";
|
||||
Size = new Size(500, 500);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
}
|
||||
}
|
||||
59
Base/Forms/Controls/PieChart.cs
Normal file
59
Base/Forms/Controls/PieChart.cs
Normal file
@ -0,0 +1,59 @@
|
||||
using System.Drawing.Drawing2D;
|
||||
|
||||
namespace Graphing.Forms.Controls;
|
||||
|
||||
public partial class PieChart : UserControl
|
||||
{
|
||||
public List<(Color, double)> Values { get; set; }
|
||||
|
||||
public PieChart()
|
||||
{
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
|
||||
Values = [];
|
||||
InitializeComponent();
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
int size = Math.Min(Width, Height);
|
||||
Rectangle rect = new(5, 5, size - 10, size - 10);
|
||||
|
||||
double sum = 0;
|
||||
foreach ((Color, double v) item in Values)
|
||||
sum += item.v;
|
||||
|
||||
// Draw them.
|
||||
double current = 0;
|
||||
foreach ((Color color, double value) item in Values)
|
||||
{
|
||||
double start = 360 * current / sum,
|
||||
end = 360 * (current + item.value) / sum;
|
||||
|
||||
Brush filler = new SolidBrush(item.color);
|
||||
g.FillPie(filler, rect, (float)start, (float)(end - start));
|
||||
|
||||
current += item.value;
|
||||
}
|
||||
|
||||
// Draw the outline.
|
||||
Pen outlinePartsPen = new(Color.FromArgb(unchecked((int)0xFF_202020)), 3);
|
||||
current = 0;
|
||||
foreach ((Color, double value) item in Values)
|
||||
{
|
||||
double start = 360 * current / sum,
|
||||
end = 360 * (current + item.value) / sum;
|
||||
g.DrawPie(outlinePartsPen, rect, (float)start, (float)(end - start));
|
||||
|
||||
current += item.value;
|
||||
}
|
||||
|
||||
// Outline
|
||||
Pen outlinePen = new(Color.FromArgb(unchecked((int)0xFF_202020)), 5);
|
||||
g.DrawEllipse(outlinePen, rect);
|
||||
}
|
||||
}
|
||||
120
Base/Forms/Controls/PieChart.resx
Normal file
120
Base/Forms/Controls/PieChart.resx
Normal file
@ -0,0 +1,120 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
</root>
|
||||
20
Base/Forms/GraphForm.Designer.cs
generated
20
Base/Forms/GraphForm.Designer.cs
generated
@ -39,6 +39,8 @@
|
||||
MenuEquations = new ToolStripMenuItem();
|
||||
MenuEquationsDerivative = new ToolStripMenuItem();
|
||||
MenuEquationsIntegral = new ToolStripMenuItem();
|
||||
MenuMisc = new ToolStripMenuItem();
|
||||
MenuMiscCaches = new ToolStripMenuItem();
|
||||
GraphMenu.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
@ -58,7 +60,7 @@
|
||||
// GraphMenu
|
||||
//
|
||||
GraphMenu.ImageScalingSize = new Size(32, 32);
|
||||
GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuColors, MenuEquations });
|
||||
GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuColors, MenuEquations, MenuMisc });
|
||||
GraphMenu.Location = new Point(0, 0);
|
||||
GraphMenu.Name = "GraphMenu";
|
||||
GraphMenu.Size = new Size(1449, 42);
|
||||
@ -125,6 +127,20 @@
|
||||
MenuEquationsIntegral.Size = new Size(360, 44);
|
||||
MenuEquationsIntegral.Text = "Compute Integral";
|
||||
//
|
||||
// MenuMisc
|
||||
//
|
||||
MenuMisc.DropDownItems.AddRange(new ToolStripItem[] { MenuMiscCaches });
|
||||
MenuMisc.Name = "MenuMisc";
|
||||
MenuMisc.Size = new Size(83, 38);
|
||||
MenuMisc.Text = "Misc";
|
||||
//
|
||||
// MenuMiscCaches
|
||||
//
|
||||
MenuMiscCaches.Name = "MenuMiscCaches";
|
||||
MenuMiscCaches.Size = new Size(359, 44);
|
||||
MenuMiscCaches.Text = "View Caches";
|
||||
MenuMiscCaches.Click += MenuMiscCaches_Click;
|
||||
//
|
||||
// GraphForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(13F, 32F);
|
||||
@ -154,5 +170,7 @@
|
||||
private ToolStripMenuItem MenuEquations;
|
||||
private ToolStripMenuItem MenuEquationsDerivative;
|
||||
private ToolStripMenuItem MenuEquationsIntegral;
|
||||
private ToolStripMenuItem MenuMisc;
|
||||
private ToolStripMenuItem MenuMiscCaches;
|
||||
}
|
||||
}
|
||||
@ -1,9 +1,16 @@
|
||||
using Graphing.Graphables;
|
||||
using Graphing.Extensions;
|
||||
using Graphing.Graphables;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Text;
|
||||
|
||||
namespace Graphing.Forms;
|
||||
|
||||
public partial class GraphForm : Form
|
||||
{
|
||||
public static readonly Color MainAxisColor = Color.Black;
|
||||
public static readonly Color SemiAxisColor = Color.FromArgb(unchecked((int)0xFF_999999));
|
||||
public static readonly Color QuarterAxisColor = Color.FromArgb(unchecked((int)0xFF_E0E0E0));
|
||||
|
||||
public Float2 ScreenCenter { get; private set; }
|
||||
public Float2 Dpi { get; private set; }
|
||||
|
||||
@ -94,7 +101,7 @@ public partial class GraphForm : Form
|
||||
double axisScale = Math.Pow(2, Math.Round(Math.Log2(ZoomLevel)));
|
||||
|
||||
// Draw horizontal/vertical quarter-axis.
|
||||
Brush quarterBrush = new SolidBrush(Color.FromArgb(unchecked((int)0xFF_E0E0E0)));
|
||||
Brush quarterBrush = new SolidBrush(QuarterAxisColor);
|
||||
Pen quarterPen = new(quarterBrush, 2);
|
||||
|
||||
for (double x = Math.Ceiling(MinVisibleGraph.x * 4 / axisScale) * axisScale / 4; x <= Math.Floor(MaxVisibleGraph.x * 4 / axisScale) * axisScale / 4; x += axisScale / 4)
|
||||
@ -111,7 +118,7 @@ public partial class GraphForm : Form
|
||||
}
|
||||
|
||||
// Draw horizontal/vertical semi-axis.
|
||||
Brush semiBrush = new SolidBrush(Color.FromArgb(unchecked((int)0xFF_999999)));
|
||||
Brush semiBrush = new SolidBrush(SemiAxisColor);
|
||||
Pen semiPen = new(semiBrush, 2);
|
||||
|
||||
for (double x = Math.Ceiling(MinVisibleGraph.x / axisScale) * axisScale; x <= Math.Floor(MaxVisibleGraph.x / axisScale) * axisScale; x += axisScale)
|
||||
@ -127,7 +134,7 @@ public partial class GraphForm : Form
|
||||
g.DrawLine(semiPen, startPos, endPos);
|
||||
}
|
||||
|
||||
Brush mainLineBrush = new SolidBrush(Color.Black);
|
||||
Brush mainLineBrush = new SolidBrush(MainAxisColor);
|
||||
Pen mainLinePen = new(mainLineBrush, 3);
|
||||
|
||||
// Draw the main axis (on top of the semi axis).
|
||||
@ -143,6 +150,7 @@ public partial class GraphForm : Form
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
|
||||
Brush background = new SolidBrush(Color.White);
|
||||
g.FillRectangle(background, e.ClipRectangle);
|
||||
@ -152,19 +160,9 @@ public partial class GraphForm : Form
|
||||
// Draw the actual graphs.
|
||||
for (int i = 0; i < ables.Count; i++)
|
||||
{
|
||||
IEnumerable<Line2d> lines = ables[i].GetItemsToRender(this);
|
||||
IEnumerable<IGraphPart> lines = ables[i].GetItemsToRender(this);
|
||||
Brush graphBrush = new SolidBrush(ables[i].Color);
|
||||
Pen penBrush = new(graphBrush, 3);
|
||||
|
||||
foreach (Line2d l in lines)
|
||||
{
|
||||
if (!double.IsNormal(l.a.x) || !double.IsNormal(l.a.y) ||
|
||||
!double.IsNormal(l.b.x) || !double.IsNormal(l.b.y)) continue;
|
||||
|
||||
Int2 start = GraphSpaceToScreenSpace(l.a),
|
||||
end = GraphSpaceToScreenSpace(l.b);
|
||||
g.DrawLine(penBrush, start, end);
|
||||
}
|
||||
foreach (IGraphPart gp in lines) gp.Render(this, g, graphBrush);
|
||||
}
|
||||
|
||||
base.OnPaint(e);
|
||||
@ -175,9 +173,9 @@ public partial class GraphForm : Form
|
||||
Invalidate(false);
|
||||
}
|
||||
|
||||
public void Graph(Graphable able)
|
||||
public void Graph(params Graphable[] able)
|
||||
{
|
||||
ables.Add(able);
|
||||
ables.AddRange(able);
|
||||
RegenerateMenuItems();
|
||||
Invalidate(false);
|
||||
}
|
||||
@ -257,14 +255,14 @@ public partial class GraphForm : Form
|
||||
colorItem.Click += (o, e) => GraphColorPickerButton_Click(able);
|
||||
MenuColors.DropDownItems.Add(colorItem);
|
||||
|
||||
if (able is Equation)
|
||||
if (able is Equation equ)
|
||||
{
|
||||
ToolStripMenuItem derivativeItem = new()
|
||||
{
|
||||
ForeColor = able.Color,
|
||||
Text = able.Name
|
||||
};
|
||||
derivativeItem.Click += (o, e) => EquationComputeDerivative_Click((able as Equation)!);
|
||||
derivativeItem.Click += (o, e) => EquationComputeDerivative_Click(equ);
|
||||
MenuEquationsDerivative.DropDownItems.Add(derivativeItem);
|
||||
|
||||
ToolStripMenuItem integralItem = new()
|
||||
@ -272,7 +270,7 @@ public partial class GraphForm : Form
|
||||
ForeColor = able.Color,
|
||||
Text = able.Name
|
||||
};
|
||||
integralItem.Click += (o, e) => EquationComputeIntegral_Click((able as Equation)!);
|
||||
integralItem.Click += (o, e) => EquationComputeIntegral_Click(equ);
|
||||
MenuEquationsIntegral.DropDownItems.Add(integralItem);
|
||||
}
|
||||
}
|
||||
@ -346,7 +344,7 @@ public partial class GraphForm : Form
|
||||
static double Integrate(EquationDelegate e, double lower, double upper)
|
||||
{
|
||||
// TODO: a better rendering method could make this much faster.
|
||||
const double step = 1e-1;
|
||||
const double step = 1e-2;
|
||||
|
||||
double factor = 1;
|
||||
if (upper < lower)
|
||||
@ -364,4 +362,16 @@ public partial class GraphForm : Form
|
||||
return sum * factor;
|
||||
}
|
||||
}
|
||||
|
||||
private void MenuMiscCaches_Click(object? sender, EventArgs e)
|
||||
{
|
||||
ViewCacheForm cacheForm = new(this)
|
||||
{
|
||||
StartPosition = FormStartPosition.Manual
|
||||
};
|
||||
|
||||
cacheForm.Location = new Point(Location.X + ClientRectangle.Width + 10,
|
||||
Location.Y + (ClientRectangle.Height - cacheForm.ClientRectangle.Height) / 2);
|
||||
cacheForm.Show();
|
||||
}
|
||||
}
|
||||
|
||||
@ -1,131 +1,119 @@
|
||||
using System;
|
||||
using System.Collections.Generic;
|
||||
using System.ComponentModel;
|
||||
using System.Data;
|
||||
using System.Drawing;
|
||||
using System.Linq;
|
||||
using System.Numerics;
|
||||
using System.Text;
|
||||
using System.Threading.Tasks;
|
||||
using System.Windows.Forms;
|
||||
namespace Graphing.Forms;
|
||||
|
||||
namespace Graphing.Forms
|
||||
public partial class SetZoomForm : Form
|
||||
{
|
||||
public partial class SetZoomForm : Form
|
||||
private double minZoomRange;
|
||||
private double maxZoomRange;
|
||||
|
||||
private double zoomLevel;
|
||||
|
||||
private readonly GraphForm form;
|
||||
|
||||
public SetZoomForm(GraphForm form)
|
||||
{
|
||||
private double minZoomRange;
|
||||
private double maxZoomRange;
|
||||
InitializeComponent();
|
||||
|
||||
private double zoomLevel;
|
||||
minZoomRange = 1 / (form.ZoomLevel * 2);
|
||||
maxZoomRange = 2 / form.ZoomLevel;
|
||||
zoomLevel = 1 / form.ZoomLevel;
|
||||
|
||||
private readonly GraphForm form;
|
||||
ZoomTrackBar.Value = (int)(ZoomToFactor(zoomLevel) * (ZoomTrackBar.Maximum - ZoomTrackBar.Minimum) + ZoomTrackBar.Minimum);
|
||||
|
||||
public SetZoomForm(GraphForm form)
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
ZoomMaxValue.Text = maxZoomRange.ToString("0.00");
|
||||
ZoomMinValue.Text = minZoomRange.ToString("0.00");
|
||||
|
||||
ValueLabel.Text = $"{zoomLevel:0.00}x";
|
||||
|
||||
base.OnPaint(e);
|
||||
|
||||
form.ZoomLevel = 1 / zoomLevel;
|
||||
form.Invalidate(false);
|
||||
}
|
||||
|
||||
private double FactorToZoom(double factor)
|
||||
{
|
||||
return minZoomRange + (factor * factor) * (maxZoomRange - minZoomRange);
|
||||
}
|
||||
private double ZoomToFactor(double zoom)
|
||||
{
|
||||
double sqrValue = (zoom - minZoomRange) / (maxZoomRange - minZoomRange);
|
||||
return Math.Sign(sqrValue) * Math.Sqrt(Math.Abs(sqrValue));
|
||||
}
|
||||
|
||||
private void ZoomTrackBar_Scroll(object? sender, EventArgs e)
|
||||
{
|
||||
double factor = (ZoomTrackBar.Value - ZoomTrackBar.Minimum) / (double)(ZoomTrackBar.Maximum - ZoomTrackBar.Minimum);
|
||||
zoomLevel = FactorToZoom(factor);
|
||||
|
||||
Invalidate(true);
|
||||
}
|
||||
|
||||
private void ZoomMinValue_TextChanged(object? sender, EventArgs e)
|
||||
{
|
||||
double original = minZoomRange;
|
||||
try
|
||||
{
|
||||
InitializeComponent();
|
||||
double value;
|
||||
if (string.IsNullOrWhiteSpace(ZoomMinValue.Text) ||
|
||||
ZoomMinValue.Text.EndsWith('.'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = double.Parse(ZoomMinValue.Text);
|
||||
if (value < 1e-2 || value > 1e3 || value > maxZoomRange) throw new();
|
||||
}
|
||||
|
||||
minZoomRange = 1 / (form.ZoomLevel * 2);
|
||||
maxZoomRange = 2 / form.ZoomLevel;
|
||||
zoomLevel = 1 / form.ZoomLevel;
|
||||
|
||||
ZoomTrackBar.Value = (int)(ZoomToFactor(zoomLevel) * (ZoomTrackBar.Maximum - ZoomTrackBar.Minimum) + ZoomTrackBar.Minimum);
|
||||
|
||||
this.form = form;
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
ZoomMaxValue.Text = maxZoomRange.ToString("0.00");
|
||||
ZoomMinValue.Text = minZoomRange.ToString("0.00");
|
||||
|
||||
ValueLabel.Text = $"{zoomLevel:0.00}x";
|
||||
|
||||
base.OnPaint(e);
|
||||
|
||||
form.ZoomLevel = 1 / zoomLevel;
|
||||
form.Invalidate(false);
|
||||
}
|
||||
|
||||
private double FactorToZoom(double factor)
|
||||
{
|
||||
return minZoomRange + (factor * factor) * (maxZoomRange - minZoomRange);
|
||||
}
|
||||
private double ZoomToFactor(double zoom)
|
||||
{
|
||||
double sqrValue = (zoom - minZoomRange) / (maxZoomRange - minZoomRange);
|
||||
return Math.Sign(sqrValue) * Math.Sqrt(Math.Abs(sqrValue));
|
||||
}
|
||||
|
||||
private void ZoomTrackBar_Scroll(object? sender, EventArgs e)
|
||||
{
|
||||
minZoomRange = value;
|
||||
ZoomTrackBar.Value = (int)Math.Clamp(ZoomToFactor(zoomLevel) * (ZoomTrackBar.Maximum - ZoomTrackBar.Minimum) + ZoomTrackBar.Minimum, ZoomTrackBar.Minimum, ZoomTrackBar.Maximum);
|
||||
double factor = (ZoomTrackBar.Value - ZoomTrackBar.Minimum) / (double)(ZoomTrackBar.Maximum - ZoomTrackBar.Minimum);
|
||||
zoomLevel = FactorToZoom(factor);
|
||||
double newZoom = FactorToZoom(factor);
|
||||
|
||||
Invalidate(true);
|
||||
zoomLevel = newZoom;
|
||||
if (newZoom != factor) Invalidate(true);
|
||||
}
|
||||
|
||||
private void ZoomMinValue_TextChanged(object? sender, EventArgs e)
|
||||
catch
|
||||
{
|
||||
double original = minZoomRange;
|
||||
try
|
||||
{
|
||||
double value;
|
||||
if (string.IsNullOrWhiteSpace(ZoomMinValue.Text) ||
|
||||
ZoomMinValue.Text.EndsWith('.'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = double.Parse(ZoomMinValue.Text);
|
||||
if (value < 1e-2 || value > 1e3 || value > maxZoomRange) throw new();
|
||||
}
|
||||
|
||||
minZoomRange = value;
|
||||
ZoomTrackBar.Value = (int)Math.Clamp(ZoomToFactor(zoomLevel) * (ZoomTrackBar.Maximum - ZoomTrackBar.Minimum) + ZoomTrackBar.Minimum, ZoomTrackBar.Minimum, ZoomTrackBar.Maximum);
|
||||
double factor = (ZoomTrackBar.Value - ZoomTrackBar.Minimum) / (double)(ZoomTrackBar.Maximum - ZoomTrackBar.Minimum);
|
||||
double newZoom = FactorToZoom(factor);
|
||||
|
||||
zoomLevel = newZoom;
|
||||
if (newZoom != factor) Invalidate(true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
minZoomRange = original;
|
||||
ZoomMinValue.Text = minZoomRange.ToString("0.00");
|
||||
}
|
||||
minZoomRange = original;
|
||||
ZoomMinValue.Text = minZoomRange.ToString("0.00");
|
||||
}
|
||||
}
|
||||
|
||||
private void ZoomMaxValue_TextChanged(object sender, EventArgs e)
|
||||
private void ZoomMaxValue_TextChanged(object sender, EventArgs e)
|
||||
{
|
||||
double original = maxZoomRange;
|
||||
try
|
||||
{
|
||||
double original = maxZoomRange;
|
||||
try
|
||||
double value;
|
||||
if (string.IsNullOrWhiteSpace(ZoomMaxValue.Text) ||
|
||||
ZoomMaxValue.Text.EndsWith('.'))
|
||||
{
|
||||
double value;
|
||||
if (string.IsNullOrWhiteSpace(ZoomMaxValue.Text) ||
|
||||
ZoomMaxValue.Text.EndsWith('.'))
|
||||
{
|
||||
return;
|
||||
}
|
||||
else
|
||||
{
|
||||
value = double.Parse(ZoomMaxValue.Text);
|
||||
if (value < 1e-2 || value > 1e3 || value < minZoomRange) throw new();
|
||||
}
|
||||
|
||||
maxZoomRange = value;
|
||||
ZoomTrackBar.Value = (int)Math.Clamp(ZoomToFactor(zoomLevel) * (ZoomTrackBar.Maximum - ZoomTrackBar.Minimum) + ZoomTrackBar.Minimum, ZoomTrackBar.Minimum, ZoomTrackBar.Maximum);
|
||||
double factor = (ZoomTrackBar.Value - ZoomTrackBar.Minimum) / (double)(ZoomTrackBar.Maximum - ZoomTrackBar.Minimum);
|
||||
double newZoom = FactorToZoom(factor);
|
||||
|
||||
zoomLevel = newZoom;
|
||||
if (newZoom != factor) Invalidate(true);
|
||||
return;
|
||||
}
|
||||
catch
|
||||
else
|
||||
{
|
||||
maxZoomRange = original;
|
||||
ZoomMaxValue.Text = maxZoomRange.ToString("0.00");
|
||||
value = double.Parse(ZoomMaxValue.Text);
|
||||
if (value < 1e-2 || value > 1e3 || value < minZoomRange) throw new();
|
||||
}
|
||||
|
||||
maxZoomRange = value;
|
||||
ZoomTrackBar.Value = (int)Math.Clamp(ZoomToFactor(zoomLevel) * (ZoomTrackBar.Maximum - ZoomTrackBar.Minimum) + ZoomTrackBar.Minimum, ZoomTrackBar.Minimum, ZoomTrackBar.Maximum);
|
||||
double factor = (ZoomTrackBar.Value - ZoomTrackBar.Minimum) / (double)(ZoomTrackBar.Maximum - ZoomTrackBar.Minimum);
|
||||
double newZoom = FactorToZoom(factor);
|
||||
|
||||
zoomLevel = newZoom;
|
||||
if (newZoom != factor) Invalidate(true);
|
||||
}
|
||||
catch
|
||||
{
|
||||
maxZoomRange = original;
|
||||
ZoomMaxValue.Text = maxZoomRange.ToString("0.00");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
97
Base/Forms/ViewCacheForm.Designer.cs
generated
Normal file
97
Base/Forms/ViewCacheForm.Designer.cs
generated
Normal file
@ -0,0 +1,97 @@
|
||||
namespace Graphing.Forms
|
||||
{
|
||||
partial class ViewCacheForm
|
||||
{
|
||||
/// <summary>
|
||||
/// Required designer variable.
|
||||
/// </summary>
|
||||
private System.ComponentModel.IContainer components = null;
|
||||
|
||||
/// <summary>
|
||||
/// Clean up any resources being used.
|
||||
/// </summary>
|
||||
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
|
||||
protected override void Dispose(bool disposing)
|
||||
{
|
||||
if (disposing && (components != null))
|
||||
{
|
||||
components.Dispose();
|
||||
}
|
||||
base.Dispose(disposing);
|
||||
}
|
||||
|
||||
#region Windows Form Designer generated code
|
||||
|
||||
/// <summary>
|
||||
/// Required method for Designer support - do not modify
|
||||
/// the contents of this method with the code editor.
|
||||
/// </summary>
|
||||
private void InitializeComponent()
|
||||
{
|
||||
System.ComponentModel.ComponentResourceManager resources = new System.ComponentModel.ComponentResourceManager(typeof(ViewCacheForm));
|
||||
CachePie = new Controls.PieChart();
|
||||
TotalCacheText = new Label();
|
||||
EraseAllCacheButton = new Button();
|
||||
SpecificCachePanel = new Panel();
|
||||
SuspendLayout();
|
||||
//
|
||||
// CachePie
|
||||
//
|
||||
CachePie.Location = new Point(50, 50);
|
||||
CachePie.Name = "CachePie";
|
||||
CachePie.Size = new Size(450, 450);
|
||||
CachePie.TabIndex = 0;
|
||||
//
|
||||
// TotalCacheText
|
||||
//
|
||||
TotalCacheText.Font = new Font("Segoe UI Semibold", 10.125F, FontStyle.Bold, GraphicsUnit.Point, 0);
|
||||
TotalCacheText.Location = new Point(62, 540);
|
||||
TotalCacheText.Name = "TotalCacheText";
|
||||
TotalCacheText.Size = new Size(425, 45);
|
||||
TotalCacheText.TabIndex = 1;
|
||||
TotalCacheText.Text = "Total Cache: Something";
|
||||
TotalCacheText.TextAlign = ContentAlignment.TopCenter;
|
||||
//
|
||||
// EraseAllCacheButton
|
||||
//
|
||||
EraseAllCacheButton.Location = new Point(200, 580);
|
||||
EraseAllCacheButton.Name = "EraseAllCacheButton";
|
||||
EraseAllCacheButton.Size = new Size(150, 46);
|
||||
EraseAllCacheButton.TabIndex = 2;
|
||||
EraseAllCacheButton.Text = "Erase All";
|
||||
EraseAllCacheButton.UseVisualStyleBackColor = true;
|
||||
EraseAllCacheButton.Click += EraseAllCacheButton_Click;
|
||||
//
|
||||
// SpecificCachePanel
|
||||
//
|
||||
SpecificCachePanel.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left | AnchorStyles.Right;
|
||||
SpecificCachePanel.AutoScroll = true;
|
||||
SpecificCachePanel.Location = new Point(520, 12);
|
||||
SpecificCachePanel.Name = "SpecificCachePanel";
|
||||
SpecificCachePanel.Size = new Size(542, 657);
|
||||
SpecificCachePanel.TabIndex = 3;
|
||||
//
|
||||
// ViewCacheForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(13F, 32F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1074, 679);
|
||||
Controls.Add(SpecificCachePanel);
|
||||
Controls.Add(EraseAllCacheButton);
|
||||
Controls.Add(TotalCacheText);
|
||||
Controls.Add(CachePie);
|
||||
FormBorderStyle = FormBorderStyle.SizableToolWindow;
|
||||
MinimumSize = new Size(885, 750);
|
||||
Name = "ViewCacheForm";
|
||||
Text = "Graph Caches";
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private Controls.PieChart CachePie;
|
||||
private Label TotalCacheText;
|
||||
private Button EraseAllCacheButton;
|
||||
private Panel SpecificCachePanel;
|
||||
}
|
||||
}
|
||||
89
Base/Forms/ViewCacheForm.cs
Normal file
89
Base/Forms/ViewCacheForm.cs
Normal file
@ -0,0 +1,89 @@
|
||||
using Graphing.Extensions;
|
||||
|
||||
namespace Graphing.Forms;
|
||||
|
||||
public partial class ViewCacheForm : Form
|
||||
{
|
||||
private readonly GraphForm refForm;
|
||||
|
||||
private readonly List<Label> labelCache;
|
||||
private readonly List<Button> buttonCache;
|
||||
|
||||
public ViewCacheForm(GraphForm thisForm)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
refForm = thisForm;
|
||||
refForm.Paint += (o, e) => UpdatePieChart();
|
||||
labelCache = [];
|
||||
buttonCache = [];
|
||||
UpdatePieChart();
|
||||
}
|
||||
|
||||
private void UpdatePieChart()
|
||||
{
|
||||
CachePie.Values.Clear();
|
||||
|
||||
long totalBytes = 0;
|
||||
int index = 0;
|
||||
foreach (Graphable able in refForm.Graphables)
|
||||
{
|
||||
long thisBytes = able.GetCacheBytes();
|
||||
CachePie.Values.Add((able.Color, thisBytes));
|
||||
totalBytes += thisBytes;
|
||||
|
||||
if (index < labelCache.Count)
|
||||
{
|
||||
Label reuseLabel = labelCache[index];
|
||||
reuseLabel.ForeColor = able.Color;
|
||||
reuseLabel.Text = $"{able.Name}: {thisBytes.FormatAsBytes()}";
|
||||
}
|
||||
else
|
||||
{
|
||||
Label newText = new()
|
||||
{
|
||||
Anchor = AnchorStyles.Left | AnchorStyles.Top | AnchorStyles.Right,
|
||||
AutoEllipsis = true,
|
||||
ForeColor = able.Color,
|
||||
Location = new Point(0, labelCache.Count * 46),
|
||||
Parent = SpecificCachePanel,
|
||||
Size = new Size(SpecificCachePanel.Width - 98, 46),
|
||||
Text = $"{able.Name}: {thisBytes.FormatAsBytes()}",
|
||||
TextAlign = ContentAlignment.MiddleLeft,
|
||||
};
|
||||
labelCache.Add(newText);
|
||||
}
|
||||
|
||||
if (index >= buttonCache.Count)
|
||||
{
|
||||
Button newButton = new()
|
||||
{
|
||||
Anchor = AnchorStyles.Top | AnchorStyles.Right,
|
||||
Location = new Point(SpecificCachePanel.Width - 92, buttonCache.Count * 46),
|
||||
Parent = SpecificCachePanel,
|
||||
Size = new Size(92, 46),
|
||||
Text = "Clear"
|
||||
};
|
||||
newButton.Click += (o, e) => EraseSpecificGraphable_Click(able);
|
||||
buttonCache.Add(newButton);
|
||||
}
|
||||
|
||||
index++;
|
||||
}
|
||||
|
||||
TotalCacheText.Text = $"Total Cache: {totalBytes.FormatAsBytes()}";
|
||||
|
||||
Invalidate(true);
|
||||
}
|
||||
|
||||
private void EraseAllCacheButton_Click(object? sender, EventArgs e)
|
||||
{
|
||||
foreach (Graphable able in refForm.Graphables) able.EraseCache();
|
||||
refForm.Invalidate(false);
|
||||
}
|
||||
private void EraseSpecificGraphable_Click(Graphable able)
|
||||
{
|
||||
able.EraseCache();
|
||||
refForm.Invalidate(false);
|
||||
}
|
||||
}
|
||||
139
Base/Forms/ViewCacheForm.resx
Normal file
139
Base/Forms/ViewCacheForm.resx
Normal file
@ -0,0 +1,139 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<root>
|
||||
<!--
|
||||
Microsoft ResX Schema
|
||||
|
||||
Version 2.0
|
||||
|
||||
The primary goals of this format is to allow a simple XML format
|
||||
that is mostly human readable. The generation and parsing of the
|
||||
various data types are done through the TypeConverter classes
|
||||
associated with the data types.
|
||||
|
||||
Example:
|
||||
|
||||
... ado.net/XML headers & schema ...
|
||||
<resheader name="resmimetype">text/microsoft-resx</resheader>
|
||||
<resheader name="version">2.0</resheader>
|
||||
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
|
||||
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
|
||||
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
|
||||
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
|
||||
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>[base64 mime encoded serialized .NET Framework object]</value>
|
||||
</data>
|
||||
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
|
||||
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
|
||||
<comment>This is a comment</comment>
|
||||
</data>
|
||||
|
||||
There are any number of "resheader" rows that contain simple
|
||||
name/value pairs.
|
||||
|
||||
Each data row contains a name, and value. The row also contains a
|
||||
type or mimetype. Type corresponds to a .NET class that support
|
||||
text/value conversion through the TypeConverter architecture.
|
||||
Classes that don't support this are serialized and stored with the
|
||||
mimetype set.
|
||||
|
||||
The mimetype is used for serialized objects, and tells the
|
||||
ResXResourceReader how to depersist the object. This is currently not
|
||||
extensible. For a given mimetype the value must be set accordingly:
|
||||
|
||||
Note - application/x-microsoft.net.object.binary.base64 is the format
|
||||
that the ResXResourceWriter will generate, however the reader can
|
||||
read any of the formats listed below.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.binary.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.soap.base64
|
||||
value : The object must be serialized with
|
||||
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
|
||||
: and then encoded with base64 encoding.
|
||||
|
||||
mimetype: application/x-microsoft.net.object.bytearray.base64
|
||||
value : The object must be serialized into a byte array
|
||||
: using a System.ComponentModel.TypeConverter
|
||||
: and then encoded with base64 encoding.
|
||||
-->
|
||||
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
|
||||
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
|
||||
<xsd:element name="root" msdata:IsDataSet="true">
|
||||
<xsd:complexType>
|
||||
<xsd:choice maxOccurs="unbounded">
|
||||
<xsd:element name="metadata">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" use="required" type="xsd:string" />
|
||||
<xsd:attribute name="type" type="xsd:string" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="assembly">
|
||||
<xsd:complexType>
|
||||
<xsd:attribute name="alias" type="xsd:string" />
|
||||
<xsd:attribute name="name" type="xsd:string" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="data">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
|
||||
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
|
||||
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
|
||||
<xsd:attribute ref="xml:space" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
<xsd:element name="resheader">
|
||||
<xsd:complexType>
|
||||
<xsd:sequence>
|
||||
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
|
||||
</xsd:sequence>
|
||||
<xsd:attribute name="name" type="xsd:string" use="required" />
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:choice>
|
||||
</xsd:complexType>
|
||||
</xsd:element>
|
||||
</xsd:schema>
|
||||
<resheader name="resmimetype">
|
||||
<value>text/microsoft-resx</value>
|
||||
</resheader>
|
||||
<resheader name="version">
|
||||
<value>2.0</value>
|
||||
</resheader>
|
||||
<resheader name="reader">
|
||||
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<resheader name="writer">
|
||||
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
|
||||
</resheader>
|
||||
<data name="CachePie.Values" mimetype="application/x-microsoft.net.object.binary.base64">
|
||||
<value>
|
||||
AAEAAAD/////AQAAAAAAAAAEAQAAAM0CU3lzdGVtLkNvbGxlY3Rpb25zLkdlbmVyaWMuTGlzdGAxW1tT
|
||||
eXN0ZW0uVmFsdWVUdXBsZWAyW1tTeXN0ZW0uRHJhd2luZy5Db2xvciwgU3lzdGVtLkRyYXdpbmcsIFZl
|
||||
cnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUw
|
||||
YTNhXSxbU3lzdGVtLkRvdWJsZSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0
|
||||
cmFsLCBQdWJsaWNLZXlUb2tlbj1iNzdhNWM1NjE5MzRlMDg5XV0sIG1zY29ybGliLCBWZXJzaW9uPTQu
|
||||
MC4wLjAsIEN1bHR1cmU9bmV1dHJhbCwgUHVibGljS2V5VG9rZW49Yjc3YTVjNTYxOTM0ZTA4OV1dAwAA
|
||||
AAZfaXRlbXMFX3NpemUIX3ZlcnNpb24DAADdAVN5c3RlbS5WYWx1ZVR1cGxlYDJbW1N5c3RlbS5EcmF3
|
||||
aW5nLkNvbG9yLCBTeXN0ZW0uRHJhd2luZywgVmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWws
|
||||
IFB1YmxpY0tleVRva2VuPWIwM2Y1ZjdmMTFkNTBhM2FdLFtTeXN0ZW0uRG91YmxlLCBtc2NvcmxpYiwg
|
||||
VmVyc2lvbj00LjAuMC4wLCBDdWx0dXJlPW5ldXRyYWwsIFB1YmxpY0tleVRva2VuPWI3N2E1YzU2MTkz
|
||||
NGUwODldXVtdCAgJAgAAAAAAAAAAAAAABwIAAAAAAQAAAAAAAAAD2wFTeXN0ZW0uVmFsdWVUdXBsZWAy
|
||||
W1tTeXN0ZW0uRHJhd2luZy5Db2xvciwgU3lzdGVtLkRyYXdpbmcsIFZlcnNpb249NC4wLjAuMCwgQ3Vs
|
||||
dHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tlbj1iMDNmNWY3ZjExZDUwYTNhXSxbU3lzdGVtLkRvdWJs
|
||||
ZSwgbXNjb3JsaWIsIFZlcnNpb249NC4wLjAuMCwgQ3VsdHVyZT1uZXV0cmFsLCBQdWJsaWNLZXlUb2tl
|
||||
bj1iNzdhNWM1NjE5MzRlMDg5XV0L
|
||||
</value>
|
||||
</data>
|
||||
</root>
|
||||
@ -1,4 +1,5 @@
|
||||
using Graphing.Forms;
|
||||
using Graphing.Parts;
|
||||
|
||||
namespace Graphing;
|
||||
|
||||
@ -26,5 +27,10 @@ public abstract class Graphable
|
||||
Name = "Unnamed Graphable.";
|
||||
}
|
||||
|
||||
public abstract IEnumerable<Line2d> GetItemsToRender(in GraphForm graph);
|
||||
public abstract IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph);
|
||||
|
||||
public abstract Graphable DeepCopy();
|
||||
|
||||
public abstract void EraseCache();
|
||||
public abstract long GetCacheBytes();
|
||||
}
|
||||
|
||||
51
Base/Graphables/ColumnTable.cs
Normal file
51
Base/Graphables/ColumnTable.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using Graphing.Forms;
|
||||
using Graphing.Parts;
|
||||
|
||||
namespace Graphing.Graphables;
|
||||
|
||||
public class ColumnTable : Graphable
|
||||
{
|
||||
private static int tableNum;
|
||||
|
||||
protected readonly Dictionary<double, double> tableXY;
|
||||
protected readonly double width;
|
||||
|
||||
public ColumnTable(double width, Dictionary<double, double> tableXY)
|
||||
{
|
||||
tableNum++;
|
||||
Name = $"Column Table {tableNum}";
|
||||
|
||||
this.tableXY = tableXY;
|
||||
this.width = width;
|
||||
}
|
||||
public ColumnTable(double step, Equation equation, double min, double max)
|
||||
{
|
||||
Name = $"Column Table for {equation.Name}";
|
||||
|
||||
tableXY = [];
|
||||
EquationDelegate equ = equation.GetDelegate();
|
||||
width = 0.75 * step;
|
||||
|
||||
double minRounded = Math.Round(min / step) * step,
|
||||
maxRounded = Math.Round(max / step) * step;
|
||||
for (double x = minRounded; x <= maxRounded; x += step)
|
||||
tableXY.Add(x, equ(x));
|
||||
}
|
||||
|
||||
public override void EraseCache() { }
|
||||
public override long GetCacheBytes() => 16 * tableXY.Count;
|
||||
|
||||
public override Graphable DeepCopy() => new ColumnTable(width / 0.75, tableXY.ToArray().ToDictionary());
|
||||
|
||||
public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph)
|
||||
{
|
||||
List<IGraphPart> items = [];
|
||||
foreach (KeyValuePair<double, double> col in tableXY)
|
||||
{
|
||||
items.Add(GraphRectangle.FromSize(new Float2(col.Key, col.Value / 2),
|
||||
new Float2(width, col.Value)));
|
||||
}
|
||||
|
||||
return items;
|
||||
}
|
||||
}
|
||||
@ -1,4 +1,5 @@
|
||||
using Graphing.Forms;
|
||||
using Graphing.Parts;
|
||||
|
||||
namespace Graphing.Graphables;
|
||||
|
||||
@ -6,7 +7,8 @@ public class Equation : Graphable
|
||||
{
|
||||
private static int equationNum;
|
||||
|
||||
private readonly EquationDelegate equ;
|
||||
protected readonly EquationDelegate equ;
|
||||
protected readonly List<Float2> cache;
|
||||
|
||||
public Equation(EquationDelegate equ)
|
||||
{
|
||||
@ -14,20 +16,27 @@ public class Equation : Graphable
|
||||
Name = $"Equation {equationNum}";
|
||||
|
||||
this.equ = equ;
|
||||
cache = [];
|
||||
}
|
||||
|
||||
public override IEnumerable<Line2d> GetItemsToRender(in GraphForm graph)
|
||||
public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph)
|
||||
{
|
||||
List<Line2d> lines = [];
|
||||
const int step = 10;
|
||||
double epsilon = Math.Abs(graph.ScreenSpaceToGraphSpace(new Int2(0, 0)).x
|
||||
- graph.ScreenSpaceToGraphSpace(new Int2(step / 2, 0)).x) / 5;
|
||||
|
||||
List<IGraphPart> lines = [];
|
||||
|
||||
double previousX = graph.MinVisibleGraph.x;
|
||||
double previousY = equ(previousX);
|
||||
for (int i = 1; i < graph.ClientRectangle.Width; i += 10)
|
||||
double previousY = GetFromCache(previousX, epsilon);
|
||||
|
||||
for (int i = 1; i < graph.ClientRectangle.Width; i += step)
|
||||
{
|
||||
double currentX = graph.ScreenSpaceToGraphSpace(new Int2(i, 0)).x;
|
||||
double currentY = equ(currentX);
|
||||
double currentY = GetFromCache(currentX, epsilon);
|
||||
if (Math.Abs(currentY - previousY) <= 10)
|
||||
{
|
||||
lines.Add(new Line2d(new Float2(previousX, previousY), new Float2(currentX, currentY)));
|
||||
lines.Add(new GraphLine(new Float2(previousX, previousY), new Float2(currentX, currentY)));
|
||||
}
|
||||
previousX = currentX;
|
||||
previousY = currentY;
|
||||
@ -36,6 +45,57 @@ public class Equation : Graphable
|
||||
}
|
||||
|
||||
public EquationDelegate GetDelegate() => equ;
|
||||
|
||||
public override void EraseCache() => cache.Clear();
|
||||
protected double GetFromCache(double x, double epsilon)
|
||||
{
|
||||
(double dist, double nearest, int index) = NearestCachedPoint(x);
|
||||
if (dist < epsilon) return nearest;
|
||||
else
|
||||
{
|
||||
double result = equ(x);
|
||||
cache.Insert(index + 1, new(x, result));
|
||||
return result;
|
||||
}
|
||||
}
|
||||
|
||||
// Pretty sure this works. Certainly works pretty well with "hard-to-compute"
|
||||
// equations.
|
||||
protected (double dist, double y, int index) NearestCachedPoint(double x)
|
||||
{
|
||||
if (cache.Count == 0) return (double.PositiveInfinity, double.NaN, -1);
|
||||
else if (cache.Count == 1)
|
||||
{
|
||||
Float2 single = cache[0];
|
||||
return (Math.Abs(single.x - x), single.y, 0);
|
||||
}
|
||||
else
|
||||
{
|
||||
int boundA = 0, boundB = cache.Count;
|
||||
do
|
||||
{
|
||||
int boundC = (boundA + boundB) / 2;
|
||||
Float2 pointC = cache[boundC];
|
||||
|
||||
if (pointC.x == x) return (0, pointC.y, boundC);
|
||||
else if (pointC.x > x)
|
||||
{
|
||||
boundA = boundC;
|
||||
}
|
||||
else // pointC.x < x
|
||||
{
|
||||
boundB = boundC;
|
||||
}
|
||||
|
||||
} while (boundB - boundA > 1);
|
||||
|
||||
return (Math.Abs(cache[boundA].x - x), cache[boundA].y, boundA);
|
||||
}
|
||||
}
|
||||
|
||||
public override Graphable DeepCopy() => new Equation(equ);
|
||||
|
||||
public override long GetCacheBytes() => cache.Count * 16;
|
||||
}
|
||||
|
||||
public delegate double EquationDelegate(double x);
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
using Graphing.Forms;
|
||||
using Graphing.Parts;
|
||||
|
||||
namespace Graphing.Graphables;
|
||||
|
||||
@ -6,8 +7,10 @@ public class SlopeField : Graphable
|
||||
{
|
||||
private static int slopeFieldNum;
|
||||
|
||||
private readonly SlopeFieldsDelegate equ;
|
||||
private readonly double detail;
|
||||
protected readonly SlopeFieldsDelegate equ;
|
||||
protected readonly int detail;
|
||||
|
||||
protected readonly List<(Float2, GraphLine)> cache;
|
||||
|
||||
public SlopeField(int detail, SlopeFieldsDelegate equ)
|
||||
{
|
||||
@ -16,25 +19,26 @@ public class SlopeField : Graphable
|
||||
|
||||
this.equ = equ;
|
||||
this.detail = detail;
|
||||
cache = [];
|
||||
}
|
||||
|
||||
public override IEnumerable<Line2d> GetItemsToRender(in GraphForm graph)
|
||||
public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph)
|
||||
{
|
||||
List<Line2d> lines = [];
|
||||
double epsilon = 1 / (detail * 2.0);
|
||||
List<IGraphPart> lines = [];
|
||||
|
||||
for (double x = Math.Ceiling(graph.MinVisibleGraph.x - 1); x < graph.MaxVisibleGraph.x + 1; x += 1 / detail)
|
||||
for (double x = Math.Ceiling(graph.MinVisibleGraph.x - 1); x < graph.MaxVisibleGraph.x + 1; x += 1.0 / detail)
|
||||
{
|
||||
for (double y = Math.Ceiling(graph.MinVisibleGraph.y - 1); y < graph.MaxVisibleGraph.y + 1; y += 1 / detail)
|
||||
for (double y = Math.Ceiling(graph.MinVisibleGraph.y - 1); y < graph.MaxVisibleGraph.y + 1; y += 1.0 / detail)
|
||||
{
|
||||
double slope = equ(x, y);
|
||||
lines.Add(MakeSlopeLine(new Float2(x, y), slope));
|
||||
lines.Add(GetFromCache(epsilon, x, y));
|
||||
}
|
||||
}
|
||||
|
||||
return lines;
|
||||
}
|
||||
|
||||
private Line2d MakeSlopeLine(Float2 position, double slope)
|
||||
protected GraphLine MakeSlopeLine(Float2 position, double slope)
|
||||
{
|
||||
double size = detail;
|
||||
|
||||
@ -46,6 +50,30 @@ public class SlopeField : Graphable
|
||||
|
||||
return new(new(position.x + dirX, position.y + dirY), new(position.x - dirX, position.y - dirY));
|
||||
}
|
||||
protected GraphLine GetFromCache(double epsilon, double x, double y)
|
||||
{
|
||||
// Probably no binary search here, though maybe it could be done
|
||||
// in terms of just one axis.
|
||||
|
||||
foreach ((Float2 p, GraphLine l) in cache)
|
||||
{
|
||||
double diffX = Math.Abs(p.x - x),
|
||||
diffY = Math.Abs(p.y - y);
|
||||
|
||||
if (diffX < epsilon && diffY < epsilon) return l;
|
||||
}
|
||||
|
||||
// Create a new value.
|
||||
double slope = equ(x, y);
|
||||
GraphLine result = MakeSlopeLine(new Float2(x, y), slope);
|
||||
cache.Add((new Float2(x, y), result));
|
||||
return result;
|
||||
}
|
||||
|
||||
public override Graphable DeepCopy() => new SlopeField(detail, equ);
|
||||
|
||||
public override void EraseCache() => cache.Clear();
|
||||
public override long GetCacheBytes() => cache.Count * 48;
|
||||
}
|
||||
|
||||
public delegate double SlopeFieldsDelegate(double x, double y);
|
||||
|
||||
51
Base/Graphables/TangentLine.cs
Normal file
51
Base/Graphables/TangentLine.cs
Normal file
@ -0,0 +1,51 @@
|
||||
using Graphing.Forms;
|
||||
using Graphing.Parts;
|
||||
|
||||
namespace Graphing.Graphables;
|
||||
|
||||
public class TangentLine : Graphable
|
||||
{
|
||||
public double Position { get; set; }
|
||||
|
||||
protected readonly Equation parent;
|
||||
protected readonly EquationDelegate parentEqu;
|
||||
|
||||
protected readonly double length;
|
||||
|
||||
public TangentLine(double length, double position, Equation parent)
|
||||
{
|
||||
Name = $"Tangent Line of {parent.Name}";
|
||||
|
||||
parentEqu = parent.GetDelegate();
|
||||
Position = position;
|
||||
this.length = length;
|
||||
this.parent = parent;
|
||||
}
|
||||
|
||||
public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph)
|
||||
{
|
||||
Float2 point = new(Position, parentEqu(Position));
|
||||
return [MakeSlopeLine(point, DerivativeAtPoint(Position)),
|
||||
new GraphUiCircle(point, 8)];
|
||||
}
|
||||
protected GraphLine MakeSlopeLine(Float2 position, double slope)
|
||||
{
|
||||
double dirX = length, dirY = slope * length;
|
||||
double magnitude = Math.Sqrt(dirX * dirX + dirY * dirY);
|
||||
|
||||
dirX /= magnitude * 2 / length;
|
||||
dirY /= magnitude * 2 / length;
|
||||
|
||||
return new(new(position.x + dirX, position.y + dirY), new(position.x - dirX, position.y - dirY));
|
||||
}
|
||||
protected double DerivativeAtPoint(double x)
|
||||
{
|
||||
const double step = 1e-3;
|
||||
return (parentEqu(x + step) - parentEqu(x)) / step;
|
||||
}
|
||||
|
||||
public override Graphable DeepCopy() => new TangentLine(length, Position, parent);
|
||||
|
||||
public override void EraseCache() { }
|
||||
public override long GetCacheBytes() => 0;
|
||||
}
|
||||
8
Base/IGraphPart.cs
Normal file
8
Base/IGraphPart.cs
Normal file
@ -0,0 +1,8 @@
|
||||
using Graphing.Forms;
|
||||
|
||||
namespace Graphing;
|
||||
|
||||
public interface IGraphPart
|
||||
{
|
||||
public void Render(in GraphForm form, in Graphics g, in Brush brush);
|
||||
}
|
||||
@ -1,18 +0,0 @@
|
||||
namespace Graphing;
|
||||
|
||||
public record struct Line2d
|
||||
{
|
||||
public Float2 a;
|
||||
public Float2 b;
|
||||
|
||||
public Line2d()
|
||||
{
|
||||
a = new();
|
||||
b = new();
|
||||
}
|
||||
public Line2d(Float2 a, Float2 b)
|
||||
{
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
}
|
||||
32
Base/Parts/GraphLine.cs
Normal file
32
Base/Parts/GraphLine.cs
Normal file
@ -0,0 +1,32 @@
|
||||
using Graphing.Forms;
|
||||
|
||||
namespace Graphing.Parts;
|
||||
|
||||
public record struct GraphLine : IGraphPart
|
||||
{
|
||||
public Float2 a;
|
||||
public Float2 b;
|
||||
|
||||
public GraphLine()
|
||||
{
|
||||
a = new();
|
||||
b = new();
|
||||
}
|
||||
public GraphLine(Float2 a, Float2 b)
|
||||
{
|
||||
this.a = a;
|
||||
this.b = b;
|
||||
}
|
||||
|
||||
public readonly void Render(in GraphForm form, in Graphics g, in Brush brush)
|
||||
{
|
||||
if (!double.IsFinite(a.x) || !double.IsFinite(a.y) ||
|
||||
!double.IsFinite(b.x) || !double.IsFinite(b.y)) return;
|
||||
|
||||
Int2 start = form.GraphSpaceToScreenSpace(a),
|
||||
end = form.GraphSpaceToScreenSpace(b);
|
||||
|
||||
Pen pen = new(brush, 3);
|
||||
g.DrawLine(pen, start, end);
|
||||
}
|
||||
}
|
||||
45
Base/Parts/GraphRectangle.cs
Normal file
45
Base/Parts/GraphRectangle.cs
Normal file
@ -0,0 +1,45 @@
|
||||
using Graphing.Forms;
|
||||
|
||||
namespace Graphing.Parts;
|
||||
|
||||
public record struct GraphRectangle : IGraphPart
|
||||
{
|
||||
public Float2 min, max;
|
||||
|
||||
public GraphRectangle()
|
||||
{
|
||||
min = new();
|
||||
max = new();
|
||||
}
|
||||
|
||||
public static GraphRectangle FromSize(Float2 center, Float2 size) => new()
|
||||
{
|
||||
min = new(center.x - size.x / 2,
|
||||
center.y - size.y / 2),
|
||||
max = new(center.x + size.x / 2,
|
||||
center.y + size.y / 2)
|
||||
};
|
||||
public static GraphRectangle FromRange(Float2 min, Float2 max) => new()
|
||||
{
|
||||
min = min,
|
||||
max = max
|
||||
};
|
||||
|
||||
public void Render(in GraphForm form, in Graphics g, in Brush brush)
|
||||
{
|
||||
if (!double.IsFinite(max.x) || !double.IsFinite(max.y) ||
|
||||
!double.IsFinite(min.x) || !double.IsFinite(min.y)) return;
|
||||
|
||||
if (min.x > max.x) (min.x, max.x) = (max.x, min.x);
|
||||
if (min.y > max.y) (min.y, max.y) = (max.y, min.y);
|
||||
|
||||
Int2 start = form.GraphSpaceToScreenSpace(min),
|
||||
end = form.GraphSpaceToScreenSpace(max);
|
||||
|
||||
Int2 size = new(end.x - start.x + 1,
|
||||
start.y - end.y);
|
||||
|
||||
if (size.x == 0 || size.y == 0) return;
|
||||
g.FillRectangle(brush, new Rectangle(start.x, end.y, size.x, size.y));
|
||||
}
|
||||
}
|
||||
31
Base/Parts/GraphUiCircle.cs
Normal file
31
Base/Parts/GraphUiCircle.cs
Normal file
@ -0,0 +1,31 @@
|
||||
using Graphing.Forms;
|
||||
|
||||
namespace Graphing.Parts;
|
||||
|
||||
public record struct GraphUiCircle : IGraphPart
|
||||
{
|
||||
public Float2 center;
|
||||
public int radius;
|
||||
|
||||
public GraphUiCircle()
|
||||
{
|
||||
center = new();
|
||||
radius = 1;
|
||||
}
|
||||
public GraphUiCircle(Float2 center, int radius)
|
||||
{
|
||||
this.center = center;
|
||||
this.radius = radius;
|
||||
}
|
||||
|
||||
public readonly void Render(in GraphForm form, in Graphics g, in Brush brush)
|
||||
{
|
||||
if (!double.IsFinite(center.x) || !double.IsFinite(center.y) ||
|
||||
!double.IsFinite(radius) || radius == 0) return;
|
||||
|
||||
Int2 centerPix = form.GraphSpaceToScreenSpace(center);
|
||||
g.FillEllipse(brush, new Rectangle(new Point(centerPix.x - radius,
|
||||
centerPix.y - radius),
|
||||
new Size(radius * 2, radius * 2)));
|
||||
}
|
||||
}
|
||||
13
Base/Properties/PublishProfiles/FolderProfile.pubxml
Normal file
13
Base/Properties/PublishProfiles/FolderProfile.pubxml
Normal file
@ -0,0 +1,13 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<Configuration>Release</Configuration>
|
||||
<Platform>Any CPU</Platform>
|
||||
<PublishDir>bin\Release\net8.0-windows\publish\</PublishDir>
|
||||
<PublishProtocol>FileSystem</PublishProtocol>
|
||||
<_TargetId>Folder</_TargetId>
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
10
Base/Properties/PublishProfiles/FolderProfile.pubxml.user
Normal file
10
Base/Properties/PublishProfiles/FolderProfile.pubxml.user
Normal file
@ -0,0 +1,10 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<!--
|
||||
https://go.microsoft.com/fwlink/?LinkID=208121.
|
||||
-->
|
||||
<Project>
|
||||
<PropertyGroup>
|
||||
<History>True|2024-03-13T14:31:43.4569441Z;False|2024-03-13T10:30:01.4347009-04:00;False|2024-03-13T10:27:31.9554551-04:00;</History>
|
||||
<LastFailureDetails />
|
||||
</PropertyGroup>
|
||||
</Project>
|
||||
@ -1,27 +0,0 @@
|
||||
namespace Graphing;
|
||||
|
||||
public record struct Range2d
|
||||
{
|
||||
public double minX;
|
||||
public double minY;
|
||||
public double maxX;
|
||||
public double maxY;
|
||||
|
||||
public Range2d()
|
||||
{
|
||||
minX = 0;
|
||||
minY = 0;
|
||||
maxX = 0;
|
||||
maxY = 0;
|
||||
}
|
||||
public Range2d(double minX, double minY, double maxX, double maxY)
|
||||
{
|
||||
this.minX = minX;
|
||||
this.minY = minY;
|
||||
this.maxX = maxX;
|
||||
this.maxY = maxY;
|
||||
}
|
||||
|
||||
public readonly bool Contains(Float2 p) =>
|
||||
p.x >= minX && p.x <= maxX && p.y >= minY && p.y <= maxY;
|
||||
}
|
||||
@ -10,10 +10,31 @@ internal static class Program
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.SetHighDpiMode(HighDpiMode.PerMonitorV2);
|
||||
Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
|
||||
GraphForm graph = new("One Of The Graphing Calculators Of All Time");
|
||||
graph.Graph(new Equation(Math.Cos));
|
||||
|
||||
Equation equ1 = new(x =>
|
||||
{
|
||||
// Demonstrate the caching abilities of the software.
|
||||
// This extra waiting is done every time the form requires a
|
||||
// calculation done. At the start, it'll be laggy, but as you
|
||||
// move around and zoom in, more pieces are cached, and when
|
||||
// you reset, the viewport will be a lot less laggy.
|
||||
|
||||
// Remove this loop to make the equation fast again. I didn't
|
||||
// slow the engine down much more with this improvement, so any
|
||||
// speed decrease you might notice is likely this function.
|
||||
for (int i = 0; i < 1_000_000; i++) ;
|
||||
return -x * x + 2;
|
||||
});
|
||||
Equation equ2 = new(x => x);
|
||||
Equation equ3 = new(x => -Math.Sqrt(x));
|
||||
SlopeField sf = new(2, (x, y) => (x * x - y * y) / x);
|
||||
graph.Graph(equ1, equ2, equ3, sf);
|
||||
|
||||
// You can also now view and reset caches in the UI by going to
|
||||
// Misc > View Caches.
|
||||
|
||||
Application.Run(graph);
|
||||
}
|
||||
|
||||
@ -1,7 +1,6 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net8.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
@ -10,6 +9,14 @@
|
||||
<AssemblyName>ThatOneNerd.Graphing.Testing</AssemblyName>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'">
|
||||
<OutputType>Exe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'">
|
||||
<OutputType>WinExe</OutputType>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<ProjectReference Include="..\Base\Base.csproj" />
|
||||
</ItemGroup>
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user