Ready for 1.1. Made a graph cache viewer.
This commit is contained in:
parent
fc829d6a6b
commit
6d8787cac7
@ -1,6 +1,9 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Compile Update="Forms\Controls\PieChart.cs">
|
||||
<SubType>UserControl</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\GraphColorPickerForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
@ -10,5 +13,8 @@
|
||||
<Compile Update="Forms\SetZoomForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\ViewCacheForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
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>
|
||||
@ -7,6 +7,10 @@ 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; }
|
||||
|
||||
@ -97,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)
|
||||
@ -114,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)
|
||||
@ -130,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).
|
||||
@ -251,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()
|
||||
@ -266,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);
|
||||
}
|
||||
}
|
||||
@ -361,23 +365,13 @@ public partial class GraphForm : Form
|
||||
|
||||
private void MenuMiscCaches_Click(object? sender, EventArgs e)
|
||||
{
|
||||
// TODO: Replace with a form with a pie chart of the use by equation
|
||||
// and the ability to reset them.
|
||||
StringBuilder message = new();
|
||||
long total = 0;
|
||||
foreach (Graphable able in ables)
|
||||
ViewCacheForm cacheForm = new(this)
|
||||
{
|
||||
long size = able.GetCacheBytes();
|
||||
message.AppendLine($"{able.Name}: {size.FormatAsBytes()}");
|
||||
total += size;
|
||||
}
|
||||
StartPosition = FormStartPosition.Manual
|
||||
};
|
||||
|
||||
message.AppendLine($"\nTotal: {total.FormatAsBytes()}\n\nErase cache?");
|
||||
|
||||
DialogResult result = MessageBox.Show(message.ToString(), "Graph Caches", MessageBoxButtons.YesNo, MessageBoxIcon.Information);
|
||||
if (result == DialogResult.Yes)
|
||||
{
|
||||
foreach (Graphable able in ables) able.EraseCache();
|
||||
}
|
||||
cacheForm.Location = new Point(Location.X + ClientRectangle.Width + 10,
|
||||
Location.Y + (ClientRectangle.Height - cacheForm.ClientRectangle.Height) / 2);
|
||||
cacheForm.Show();
|
||||
}
|
||||
}
|
||||
|
||||
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>
|
||||
@ -7,8 +7,8 @@ public class ColumnTable : Graphable
|
||||
{
|
||||
private static int tableNum;
|
||||
|
||||
private readonly Dictionary<double, double> tableXY;
|
||||
private readonly double width;
|
||||
protected readonly Dictionary<double, double> tableXY;
|
||||
protected readonly double width;
|
||||
|
||||
public ColumnTable(double width, Dictionary<double, double> tableXY)
|
||||
{
|
||||
|
||||
@ -7,8 +7,8 @@ public class Equation : Graphable
|
||||
{
|
||||
private static int equationNum;
|
||||
|
||||
private readonly EquationDelegate equ;
|
||||
private readonly List<Float2> cache;
|
||||
protected readonly EquationDelegate equ;
|
||||
protected readonly List<Float2> cache;
|
||||
|
||||
public Equation(EquationDelegate equ)
|
||||
{
|
||||
@ -47,7 +47,7 @@ public class Equation : Graphable
|
||||
public EquationDelegate GetDelegate() => equ;
|
||||
|
||||
public override void EraseCache() => cache.Clear();
|
||||
private double GetFromCache(double x, double epsilon)
|
||||
protected double GetFromCache(double x, double epsilon)
|
||||
{
|
||||
(double dist, double nearest, int index) = NearestCachedPoint(x);
|
||||
if (dist < epsilon) return nearest;
|
||||
@ -61,7 +61,7 @@ public class Equation : Graphable
|
||||
|
||||
// Pretty sure this works. Certainly works pretty well with "hard-to-compute"
|
||||
// equations.
|
||||
private (double dist, double y, int index) NearestCachedPoint(double x)
|
||||
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)
|
||||
|
||||
@ -7,10 +7,10 @@ public class SlopeField : Graphable
|
||||
{
|
||||
private static int slopeFieldNum;
|
||||
|
||||
private readonly SlopeFieldsDelegate equ;
|
||||
private readonly int detail;
|
||||
protected readonly SlopeFieldsDelegate equ;
|
||||
protected readonly int detail;
|
||||
|
||||
private readonly List<(Float2, GraphLine)> cache;
|
||||
protected readonly List<(Float2, GraphLine)> cache;
|
||||
|
||||
public SlopeField(int detail, SlopeFieldsDelegate equ)
|
||||
{
|
||||
@ -24,12 +24,12 @@ public class SlopeField : Graphable
|
||||
|
||||
public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph)
|
||||
{
|
||||
double epsilon = 1 / (detail * 2);
|
||||
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)
|
||||
{
|
||||
lines.Add(GetFromCache(epsilon, x, y));
|
||||
}
|
||||
@ -38,7 +38,7 @@ public class SlopeField : Graphable
|
||||
return lines;
|
||||
}
|
||||
|
||||
private GraphLine MakeSlopeLine(Float2 position, double slope)
|
||||
protected GraphLine MakeSlopeLine(Float2 position, double slope)
|
||||
{
|
||||
double size = detail;
|
||||
|
||||
@ -50,7 +50,7 @@ public class SlopeField : Graphable
|
||||
|
||||
return new(new(position.x + dirX, position.y + dirY), new(position.x - dirX, position.y - dirY));
|
||||
}
|
||||
private GraphLine GetFromCache(double epsilon, double x, double y)
|
||||
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.
|
||||
|
||||
@ -7,10 +7,10 @@ public class TangentLine : Graphable
|
||||
{
|
||||
public double Position { get; set; }
|
||||
|
||||
private readonly Equation parent;
|
||||
private readonly EquationDelegate parentEqu;
|
||||
protected readonly Equation parent;
|
||||
protected readonly EquationDelegate parentEqu;
|
||||
|
||||
private readonly double length;
|
||||
protected readonly double length;
|
||||
|
||||
public TangentLine(double length, double position, Equation parent)
|
||||
{
|
||||
@ -28,7 +28,7 @@ public class TangentLine : Graphable
|
||||
return [MakeSlopeLine(point, DerivativeAtPoint(Position)),
|
||||
new GraphUiCircle(point, 8)];
|
||||
}
|
||||
private GraphLine MakeSlopeLine(Float2 position, double slope)
|
||||
protected GraphLine MakeSlopeLine(Float2 position, double slope)
|
||||
{
|
||||
double dirX = length, dirY = slope * length;
|
||||
double magnitude = Math.Sqrt(dirX * dirX + dirY * dirY);
|
||||
@ -38,7 +38,7 @@ public class TangentLine : Graphable
|
||||
|
||||
return new(new(position.x + dirX, position.y + dirY), new(position.x - dirX, position.y - dirY));
|
||||
}
|
||||
private double DerivativeAtPoint(double x)
|
||||
protected double DerivativeAtPoint(double x)
|
||||
{
|
||||
const double step = 1e-3;
|
||||
return (parentEqu(x + step) - parentEqu(x)) / step;
|
||||
|
||||
@ -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;
|
||||
}
|
||||
@ -14,17 +14,27 @@ internal static class Program
|
||||
|
||||
GraphForm graph = new("One Of The Graphing Calculators Of All Time");
|
||||
|
||||
Equation equ = new(x =>
|
||||
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;
|
||||
return -x * x + 2;
|
||||
});
|
||||
graph.Graph(equ);
|
||||
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);
|
||||
}
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user