From 24828e9922bc4587823987efc489290b780a5c3f Mon Sep 17 00:00:00 2001 From: That_One_Nerd Date: Fri, 22 Mar 2024 09:56:19 -0400 Subject: [PATCH] Did tangent line conversion, reworked some of the UI, and started shifting. --- Base/Abstract/IEquationConvertible.cs | 8 ++ Base/Abstract/ITranslatable.cs | 3 + Base/Abstract/ITranslatableX.cs | 6 + Base/Abstract/ITranslatableXY.cs | 3 + Base/Abstract/ITranslatableY.cs | 6 + Base/Base.csproj.user | 3 + Base/Forms/GraphForm.Designer.cs | 98 ++++++++++---- Base/Forms/GraphForm.cs | 84 ++++++++++-- Base/Forms/TranslateForm.Designer.cs | 46 +++++++ Base/Forms/TranslateForm.cs | 25 ++++ Base/Forms/TranslateForm.resx | 120 ++++++++++++++++++ Base/Graphables/Equation.cs | 25 +++- Base/Graphables/TangentLine.cs | 36 +++++- .../PublishProfiles/FolderProfile.pubxml.user | 2 +- 14 files changed, 411 insertions(+), 54 deletions(-) create mode 100644 Base/Abstract/IEquationConvertible.cs create mode 100644 Base/Abstract/ITranslatable.cs create mode 100644 Base/Abstract/ITranslatableX.cs create mode 100644 Base/Abstract/ITranslatableXY.cs create mode 100644 Base/Abstract/ITranslatableY.cs create mode 100644 Base/Forms/TranslateForm.Designer.cs create mode 100644 Base/Forms/TranslateForm.cs create mode 100644 Base/Forms/TranslateForm.resx diff --git a/Base/Abstract/IEquationConvertible.cs b/Base/Abstract/IEquationConvertible.cs new file mode 100644 index 0000000..11bcfc5 --- /dev/null +++ b/Base/Abstract/IEquationConvertible.cs @@ -0,0 +1,8 @@ +using Graphing.Graphables; + +namespace Graphing.Abstract; + +public interface IEquationConvertible +{ + public Equation ToEquation(); +} diff --git a/Base/Abstract/ITranslatable.cs b/Base/Abstract/ITranslatable.cs new file mode 100644 index 0000000..0f9e8a5 --- /dev/null +++ b/Base/Abstract/ITranslatable.cs @@ -0,0 +1,3 @@ +namespace Graphing.Abstract; + +public interface ITranslatable { } diff --git a/Base/Abstract/ITranslatableX.cs b/Base/Abstract/ITranslatableX.cs new file mode 100644 index 0000000..ed13456 --- /dev/null +++ b/Base/Abstract/ITranslatableX.cs @@ -0,0 +1,6 @@ +namespace Graphing.Abstract; + +public interface ITranslatableX : ITranslatable +{ + public double OffsetX { get; set; } +} diff --git a/Base/Abstract/ITranslatableXY.cs b/Base/Abstract/ITranslatableXY.cs new file mode 100644 index 0000000..6414127 --- /dev/null +++ b/Base/Abstract/ITranslatableXY.cs @@ -0,0 +1,3 @@ +namespace Graphing.Abstract; + +public interface ITranslatableXY : ITranslatableX, ITranslatableY { } diff --git a/Base/Abstract/ITranslatableY.cs b/Base/Abstract/ITranslatableY.cs new file mode 100644 index 0000000..f7ad103 --- /dev/null +++ b/Base/Abstract/ITranslatableY.cs @@ -0,0 +1,6 @@ +namespace Graphing.Abstract; + +public interface ITranslatableY : ITranslatable +{ + public double OffsetY { get; set; } +} diff --git a/Base/Base.csproj.user b/Base/Base.csproj.user index ef577eb..b8c9d44 100644 --- a/Base/Base.csproj.user +++ b/Base/Base.csproj.user @@ -16,6 +16,9 @@ Form + + Form + Form diff --git a/Base/Forms/GraphForm.Designer.cs b/Base/Forms/GraphForm.Designer.cs index f30584b..6ad42fb 100644 --- a/Base/Forms/GraphForm.Designer.cs +++ b/Base/Forms/GraphForm.Designer.cs @@ -38,13 +38,18 @@ namespace Graphing.Forms ButtonViewportSetCenter = new ToolStripMenuItem(); ButtonViewportReset = new ToolStripMenuItem(); ButtonViewportResetWindow = new ToolStripMenuItem(); - MenuColors = new ToolStripMenuItem(); - MenuEquations = new ToolStripMenuItem(); - MenuEquationsDerivative = new ToolStripMenuItem(); - MenuEquationsIntegral = new ToolStripMenuItem(); + MenuElements = new ToolStripMenuItem(); + MenuElementsColors = new ToolStripMenuItem(); + MenuElementsRemove = new ToolStripMenuItem(); + MenuOperations = new ToolStripMenuItem(); + MenuOperationsDerivative = new ToolStripMenuItem(); + MenuOperationsIntegral = new ToolStripMenuItem(); + MenuConvert = new ToolStripMenuItem(); + MenuConvertEquation = new ToolStripMenuItem(); MenuMisc = new ToolStripMenuItem(); MenuMiscCaches = new ToolStripMenuItem(); MiscMenuPreload = new ToolStripMenuItem(); + MenuOperationsTranslate = new ToolStripMenuItem(); GraphMenu.SuspendLayout(); SuspendLayout(); // @@ -64,7 +69,7 @@ namespace Graphing.Forms // GraphMenu // GraphMenu.ImageScalingSize = new Size(32, 32); - GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuColors, MenuEquations, MenuMisc }); + GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuElements, MenuOperations, MenuConvert, MenuMisc }); GraphMenu.Location = new Point(0, 0); GraphMenu.Name = "GraphMenu"; GraphMenu.Size = new Size(1449, 42); @@ -106,30 +111,56 @@ namespace Graphing.Forms ButtonViewportResetWindow.Text = "Reset Window Size"; ButtonViewportResetWindow.Click += ButtonViewportResetWindow_Click; // - // MenuColors + // MenuElements // - MenuColors.Name = "MenuColors"; - MenuColors.Size = new Size(101, 38); - MenuColors.Text = "Colors"; + MenuElements.DropDownItems.AddRange(new ToolStripItem[] { MenuElementsColors, MenuElementsRemove }); + MenuElements.Name = "MenuElements"; + MenuElements.Size = new Size(131, 38); + MenuElements.Text = "Elements"; // - // MenuEquations + // MenuElementsColors // - MenuEquations.DropDownItems.AddRange(new ToolStripItem[] { MenuEquationsDerivative, MenuEquationsIntegral }); - MenuEquations.Name = "MenuEquations"; - MenuEquations.Size = new Size(138, 38); - MenuEquations.Text = "Equations"; + MenuElementsColors.Name = "MenuElementsColors"; + MenuElementsColors.Size = new Size(359, 44); + MenuElementsColors.Text = "Colors"; // - // MenuEquationsDerivative + // MenuElementsRemove // - MenuEquationsDerivative.Name = "MenuEquationsDerivative"; - MenuEquationsDerivative.Size = new Size(360, 44); - MenuEquationsDerivative.Text = "Compute Derivative"; + MenuElementsRemove.Name = "MenuElementsRemove"; + MenuElementsRemove.Size = new Size(359, 44); + MenuElementsRemove.Text = "Remove"; // - // MenuEquationsIntegral + // MenuOperations // - MenuEquationsIntegral.Name = "MenuEquationsIntegral"; - MenuEquationsIntegral.Size = new Size(360, 44); - MenuEquationsIntegral.Text = "Compute Integral"; + MenuOperations.DropDownItems.AddRange(new ToolStripItem[] { MenuOperationsDerivative, MenuOperationsIntegral, MenuOperationsTranslate }); + MenuOperations.Name = "MenuOperations"; + MenuOperations.Size = new Size(151, 38); + MenuOperations.Text = "Operations"; + // + // MenuOperationsDerivative + // + MenuOperationsDerivative.Name = "MenuOperationsDerivative"; + MenuOperationsDerivative.Size = new Size(360, 44); + MenuOperationsDerivative.Text = "Compute Derivative"; + // + // MenuOperationsIntegral + // + MenuOperationsIntegral.Name = "MenuOperationsIntegral"; + MenuOperationsIntegral.Size = new Size(360, 44); + MenuOperationsIntegral.Text = "Compute Integral"; + // + // MenuConvert + // + MenuConvert.DropDownItems.AddRange(new ToolStripItem[] { MenuConvertEquation }); + MenuConvert.Name = "MenuConvert"; + MenuConvert.Size = new Size(118, 38); + MenuConvert.Text = "Convert"; + // + // MenuConvertEquation + // + MenuConvertEquation.Name = "MenuConvertEquation"; + MenuConvertEquation.Size = new Size(273, 44); + MenuConvertEquation.Text = "To Equation"; // // MenuMisc // @@ -141,17 +172,23 @@ namespace Graphing.Forms // MenuMiscCaches // MenuMiscCaches.Name = "MenuMiscCaches"; - MenuMiscCaches.Size = new Size(359, 44); + MenuMiscCaches.Size = new Size(299, 44); MenuMiscCaches.Text = "View Caches"; MenuMiscCaches.Click += MenuMiscCaches_Click; // // MiscMenuPreload // MiscMenuPreload.Name = "MiscMenuPreload"; - MiscMenuPreload.Size = new Size(359, 44); + MiscMenuPreload.Size = new Size(299, 44); MiscMenuPreload.Text = "Preload Cache"; MiscMenuPreload.Click += MiscMenuPreload_Click; // + // MenuOperationsTranslate + // + MenuOperationsTranslate.Name = "MenuOperationsTranslate"; + MenuOperationsTranslate.Size = new Size(360, 44); + MenuOperationsTranslate.Text = "Translate"; + // // GraphForm // AutoScaleDimensions = new SizeF(13F, 32F); @@ -172,17 +209,22 @@ namespace Graphing.Forms private Button ResetViewportButton; private MenuStrip GraphMenu; - private ToolStripMenuItem MenuColors; private ToolStripMenuItem MenuViewport; private ToolStripMenuItem ButtonViewportSetZoom; private ToolStripMenuItem ButtonViewportSetCenter; private ToolStripMenuItem ButtonViewportReset; private ToolStripMenuItem ButtonViewportResetWindow; - private ToolStripMenuItem MenuEquations; - private ToolStripMenuItem MenuEquationsDerivative; - private ToolStripMenuItem MenuEquationsIntegral; + private ToolStripMenuItem MenuOperations; + private ToolStripMenuItem MenuOperationsDerivative; + private ToolStripMenuItem MenuOperationsIntegral; private ToolStripMenuItem MenuMisc; private ToolStripMenuItem MenuMiscCaches; private ToolStripMenuItem MiscMenuPreload; + private ToolStripMenuItem MenuConvert; + private ToolStripMenuItem MenuConvertEquation; + private ToolStripMenuItem MenuElements; + private ToolStripMenuItem MenuElementsColors; + private ToolStripMenuItem MenuElementsRemove; + private ToolStripMenuItem MenuOperationsTranslate; } } \ No newline at end of file diff --git a/Base/Forms/GraphForm.cs b/Base/Forms/GraphForm.cs index 152d852..b1b0588 100644 --- a/Base/Forms/GraphForm.cs +++ b/Base/Forms/GraphForm.cs @@ -255,9 +255,15 @@ public partial class GraphForm : Form Invalidate(false); } - public void Graph(params Graphable[] able) + public void Graph(params Graphable[] newAbles) { - ables.AddRange(able); + ables.AddRange(newAbles); + RegenerateMenuItems(); + Invalidate(false); + } + public void Ungraph(params Graphable[] ables) + { + this.ables.RemoveAll(x => ables.Contains(x)); RegenerateMenuItems(); Invalidate(false); } @@ -348,9 +354,12 @@ public partial class GraphForm : Form private void RegenerateMenuItems() { - MenuColors.DropDownItems.Clear(); - MenuEquationsDerivative.DropDownItems.Clear(); - MenuEquationsIntegral.DropDownItems.Clear(); + MenuElementsColors.DropDownItems.Clear(); + MenuElementsRemove.DropDownItems.Clear(); + MenuOperationsDerivative.DropDownItems.Clear(); + MenuOperationsIntegral.DropDownItems.Clear(); + MenuConvertEquation.DropDownItems.Clear(); + MenuOperationsTranslate.DropDownItems.Clear(); foreach (Graphable able in ables) { @@ -360,7 +369,15 @@ public partial class GraphForm : Form Text = able.Name }; colorItem.Click += (o, e) => GraphColorPickerButton_Click(able); - MenuColors.DropDownItems.Add(colorItem); + MenuElementsColors.DropDownItems.Add(colorItem); + + ToolStripMenuItem removeItem = new() + { + ForeColor = able.Color, + Text = able.Name + }; + removeItem.Click += (o, e) => Ungraph(able); + MenuElementsRemove.DropDownItems.Add(removeItem); if (able is IDerivable derivable) { @@ -370,7 +387,7 @@ public partial class GraphForm : Form Text = able.Name }; derivativeItem.Click += (o, e) => Graph(derivable.Derive()); - MenuEquationsDerivative.DropDownItems.Add(derivativeItem); + MenuOperationsDerivative.DropDownItems.Add(derivativeItem); } if (able is IIntegrable integrable) { @@ -380,20 +397,48 @@ public partial class GraphForm : Form Text = able.Name }; integralItem.Click += (o, e) => Graph(integrable.Integrate()); - MenuEquationsIntegral.DropDownItems.Add(integralItem); + MenuOperationsIntegral.DropDownItems.Add(integralItem); + } + if (able is IEquationConvertible equConvert) + { + ToolStripMenuItem equItem = new() + { + ForeColor = able.Color, + Text = able.Name + }; + equItem.Click += (o, e) => + { + Ungraph(able); + Graph(equConvert.ToEquation()); + }; + MenuConvertEquation.DropDownItems.Add(equItem); + } + if (able is ITranslatable translatable) + { + ToolStripMenuItem transItem = new() + { + ForeColor = able.Color, + Text = able.Name + }; + transItem.Click += (o, e) => ElementsOperationsTranslate_Click(able, translatable); + MenuOperationsTranslate.DropDownItems.Add(transItem); } } } private void ButtonViewportSetZoom_Click(object? sender, EventArgs e) { - SetZoomForm picker = new(this) + SetZoomForm zoomer = new(this) { StartPosition = FormStartPosition.Manual, }; - picker.Location = new Point(Location.X + ClientRectangle.Width + 10, - Location.Y + (ClientRectangle.Height - picker.ClientRectangle.Height) / 2); - picker.ShowDialog(); + zoomer.Location = new Point(Location.X + ClientRectangle.Width + 10, + Location.Y + (ClientRectangle.Height - zoomer.ClientRectangle.Height) / 2); + if (zoomer.Location.X + zoomer.Width > Screen.FromControl(this).WorkingArea.Width) + { + zoomer.StartPosition = FormStartPosition.WindowsDefaultLocation; + } + zoomer.ShowDialog(); } private void ButtonViewportSetCenter_Click(object? sender, EventArgs e) { @@ -446,4 +491,19 @@ public partial class GraphForm : Form foreach (Graphable able in Graphables) able.Preload(xRange, yRange, step); Invalidate(false); } + + private void ElementsOperationsTranslate_Click(Graphable ableRaw, ITranslatable ableTrans) + { + TranslateForm shifter = new(this, ableRaw, ableTrans) + { + StartPosition = FormStartPosition.Manual, + }; + shifter.Location = new Point(Location.X + ClientRectangle.Width + 10, + Location.Y + (ClientRectangle.Height - shifter.ClientRectangle.Height) / 2); + if (shifter.Location.X + shifter.Width > Screen.FromControl(this).WorkingArea.Width) + { + shifter.StartPosition = FormStartPosition.WindowsDefaultLocation; + } + shifter.ShowDialog(); + } } diff --git a/Base/Forms/TranslateForm.Designer.cs b/Base/Forms/TranslateForm.Designer.cs new file mode 100644 index 0000000..058a9fe --- /dev/null +++ b/Base/Forms/TranslateForm.Designer.cs @@ -0,0 +1,46 @@ +namespace Graphing.Forms +{ + partial class TranslateForm + { + /// + /// Required designer variable. + /// + private System.ComponentModel.IContainer components = null; + + /// + /// Clean up any resources being used. + /// + /// true if managed resources should be disposed; otherwise, false. + protected override void Dispose(bool disposing) + { + if (disposing && (components != null)) + { + components.Dispose(); + } + base.Dispose(disposing); + } + + #region Windows Form Designer generated code + + /// + /// Required method for Designer support - do not modify + /// the contents of this method with the code editor. + /// + private void InitializeComponent() + { + SuspendLayout(); + // + // TranslateForm + // + AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F); + AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font; + ClientSize = new System.Drawing.Size(674, 629); + FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow; + Name = "TranslateForm"; + Text = "TranslateForm"; + ResumeLayout(false); + } + + #endregion + } +} \ No newline at end of file diff --git a/Base/Forms/TranslateForm.cs b/Base/Forms/TranslateForm.cs new file mode 100644 index 0000000..775b8ce --- /dev/null +++ b/Base/Forms/TranslateForm.cs @@ -0,0 +1,25 @@ +using Graphing.Abstract; +using System.Windows.Forms; + +namespace Graphing.Forms; + +public partial class TranslateForm : Form +{ + private readonly GraphForm refForm; + + // These variables both represent the same graphable. + private readonly Graphable ableRaw; + private readonly ITranslatable ableTrans; + + public TranslateForm(GraphForm graph, Graphable ableRaw, ITranslatable ableTrans) + { + refForm = graph; + this.ableRaw = ableRaw; + this.ableTrans = ableTrans; + + if (ableTrans is ITranslatableX transX) transX.OffsetX = 1; + if (ableTrans is ITranslatableY transY) transY.OffsetY = 1; + + graph.Invalidate(false); + } +} diff --git a/Base/Forms/TranslateForm.resx b/Base/Forms/TranslateForm.resx new file mode 100644 index 0000000..af32865 --- /dev/null +++ b/Base/Forms/TranslateForm.resx @@ -0,0 +1,120 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 2.0 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + \ No newline at end of file diff --git a/Base/Graphables/Equation.cs b/Base/Graphables/Equation.cs index c3dfa4e..da7fa61 100644 --- a/Base/Graphables/Equation.cs +++ b/Base/Graphables/Equation.cs @@ -6,13 +6,18 @@ using System.Collections.Generic; namespace Graphing.Graphables; -public class Equation : Graphable, IIntegrable, IDerivable +public class Equation : Graphable, IIntegrable, IDerivable, ITranslatableXY { private static int equationNum; + public double OffsetX { get; set; } + public double OffsetY { get; set; } + protected readonly EquationDelegate equ; protected readonly List cache; + public event Action OnInvalidate; + public Equation(EquationDelegate equ) { equationNum++; @@ -20,6 +25,11 @@ public class Equation : Graphable, IIntegrable, IDerivable this.equ = equ; cache = []; + + OffsetX = 0; + OffsetY = 0; + + OnInvalidate = delegate { }; } public override IEnumerable GetItemsToRender(in GraphForm graph) @@ -46,6 +56,7 @@ public class Equation : Graphable, IIntegrable, IDerivable previousX = currentX; previousY = currentY; } + OnInvalidate.Invoke(graph); return lines; } @@ -61,16 +72,18 @@ public class Equation : Graphable, IIntegrable, IDerivable 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; + (double dist, double nearest, int index) = NearestCachedPoint(x - OffsetX); + if (dist < epsilon) return nearest + OffsetY; else { - double result = equ(x); - cache.Insert(index + 1, new(x, result)); - return result; + double result = equ(x - OffsetX); + cache.Insert(index + 1, new(x - OffsetX, result)); + return result + OffsetY; } } + public double GetValueAt(double x) => GetFromCache(x, 0); + protected (double dist, double y, int index) NearestCachedPoint(double x) { if (cache.Count == 0) return (double.PositiveInfinity, double.NaN, -1); diff --git a/Base/Graphables/TangentLine.cs b/Base/Graphables/TangentLine.cs index f22eec0..9f5c2e1 100644 --- a/Base/Graphables/TangentLine.cs +++ b/Base/Graphables/TangentLine.cs @@ -1,11 +1,12 @@ -using Graphing.Forms; +using Graphing.Abstract; +using Graphing.Forms; using Graphing.Parts; using System; using System.Collections.Generic; namespace Graphing.Graphables; -public class TangentLine : Graphable +public class TangentLine : Graphable, IEquationConvertible, ITranslatableX { public double Position { @@ -18,8 +19,13 @@ public class TangentLine : Graphable } private double _position; // Private because it has exactly the same functionality as `Position`. + public double OffsetX + { + get => Position; + set => Position = value; + } + protected readonly Equation parent; - protected readonly EquationDelegate parentEqu; protected readonly double length; @@ -35,10 +41,16 @@ public class TangentLine : Graphable Name = $"Tangent Line of {parent.Name}"; slopeCache = []; - parentEqu = parent.GetDelegate(); - Position = position; this.length = length; this.parent = parent; + Position = position; + + parent.OnInvalidate += (graph) => + { + // I don't love this but it works. + EraseCache(); + Position = _position; // Done for side effects. + }; } public override IEnumerable GetItemsToRender(in GraphForm graph) @@ -63,8 +75,8 @@ public class TangentLine : Graphable const double step = 1e-3; - double initial = parentEqu(x); - Float2 result = new((parentEqu(x + step) - initial) / step, initial); + double initial = parent.GetValueAt(x); + Float2 result = new((parent.GetValueAt(x + step) - initial) / step, initial); slopeCache.Add(x, result); return result; } @@ -112,4 +124,14 @@ public class TangentLine : Graphable // that can be changed. for (double x = xRange.x; x <= xRange.y; x += step) DerivativeAtPoint(x); } + + public Equation ToEquation() + { + double slope = currentSlope.x, x1 = Position, y1 = currentSlope.y; + return new(x => slope * (x - x1) + y1) + { + Name = Name, + Color = Color + }; + } } diff --git a/Base/Properties/PublishProfiles/FolderProfile.pubxml.user b/Base/Properties/PublishProfiles/FolderProfile.pubxml.user index 706348e..4da2d5e 100644 --- a/Base/Properties/PublishProfiles/FolderProfile.pubxml.user +++ b/Base/Properties/PublishProfiles/FolderProfile.pubxml.user @@ -4,7 +4,7 @@ https://go.microsoft.com/fwlink/?LinkID=208121. --> - True|2024-03-20T12:39:01.6402921Z;True|2024-03-13T10:31:43.4569441-04:00;False|2024-03-13T10:30:01.4347009-04:00;False|2024-03-13T10:27:31.9554551-04:00; + True|2024-03-20T12:48:45.8740885Z;True|2024-03-20T08:48:35.6948867-04:00;True|2024-03-20T08:39:01.6402921-04:00;True|2024-03-13T10:31:43.4569441-04:00;False|2024-03-13T10:30:01.4347009-04:00;False|2024-03-13T10:27:31.9554551-04:00; \ No newline at end of file