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