diff --git a/Base/Base.csproj.user b/Base/Base.csproj.user
index b8c9d44..8d9b1c8 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 2de0a19..ec64887 100644
--- a/Base/Forms/GraphForm.Designer.cs
+++ b/Base/Forms/GraphForm.Designer.cs
@@ -55,6 +55,7 @@ namespace Graphing.Forms
UpdaterPopupDownloadButton = new Button();
UpdaterPopupCloseButton = new Button();
UpdaterPopupMessage = new Label();
+ MenuElementsDetail = new ToolStripMenuItem();
GraphMenu.SuspendLayout();
UpdaterPopup.SuspendLayout();
SuspendLayout();
@@ -63,10 +64,10 @@ namespace Graphing.Forms
//
ResetViewportButton.Anchor = AnchorStyles.Top | AnchorStyles.Right;
ResetViewportButton.Font = new Font("Segoe UI Emoji", 12F, FontStyle.Regular, GraphicsUnit.Point, 0);
- ResetViewportButton.Location = new Point(739, 20);
- ResetViewportButton.Margin = new Padding(2, 1, 2, 1);
+ ResetViewportButton.Location = new Point(1372, 43);
+ ResetViewportButton.Margin = new Padding(4, 2, 4, 2);
ResetViewportButton.Name = "ResetViewportButton";
- ResetViewportButton.Size = new Size(34, 30);
+ ResetViewportButton.Size = new Size(63, 64);
ResetViewportButton.TabIndex = 0;
ResetViewportButton.Text = "🏠";
ResetViewportButton.UseVisualStyleBackColor = true;
@@ -78,8 +79,7 @@ namespace Graphing.Forms
GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuElements, MenuOperations, MenuConvert, MenuMisc });
GraphMenu.Location = new Point(0, 0);
GraphMenu.Name = "GraphMenu";
- GraphMenu.Padding = new Padding(3, 1, 0, 1);
- GraphMenu.Size = new Size(780, 24);
+ GraphMenu.Size = new Size(1449, 42);
GraphMenu.TabIndex = 1;
GraphMenu.Text = "menuStrip1";
//
@@ -87,118 +87,118 @@ namespace Graphing.Forms
//
MenuViewport.DropDownItems.AddRange(new ToolStripItem[] { ButtonViewportSetZoom, ButtonViewportSetCenter, ButtonViewportReset, ButtonViewportResetWindow });
MenuViewport.Name = "MenuViewport";
- MenuViewport.Size = new Size(66, 22);
+ MenuViewport.Size = new Size(129, 38);
MenuViewport.Text = "Viewport";
//
// ButtonViewportSetZoom
//
ButtonViewportSetZoom.Name = "ButtonViewportSetZoom";
- ButtonViewportSetZoom.Size = new Size(174, 22);
+ ButtonViewportSetZoom.Size = new Size(359, 44);
ButtonViewportSetZoom.Text = "Set Zoom";
ButtonViewportSetZoom.Click += ButtonViewportSetZoom_Click;
//
// ButtonViewportSetCenter
//
ButtonViewportSetCenter.Name = "ButtonViewportSetCenter";
- ButtonViewportSetCenter.Size = new Size(174, 22);
+ ButtonViewportSetCenter.Size = new Size(359, 44);
ButtonViewportSetCenter.Text = "Set Center Position";
ButtonViewportSetCenter.Click += ButtonViewportSetCenter_Click;
//
// ButtonViewportReset
//
ButtonViewportReset.Name = "ButtonViewportReset";
- ButtonViewportReset.Size = new Size(174, 22);
+ ButtonViewportReset.Size = new Size(359, 44);
ButtonViewportReset.Text = "Reset Viewport";
ButtonViewportReset.Click += ButtonViewportReset_Click;
//
// ButtonViewportResetWindow
//
ButtonViewportResetWindow.Name = "ButtonViewportResetWindow";
- ButtonViewportResetWindow.Size = new Size(174, 22);
+ ButtonViewportResetWindow.Size = new Size(359, 44);
ButtonViewportResetWindow.Text = "Reset Window Size";
ButtonViewportResetWindow.Click += ButtonViewportResetWindow_Click;
//
// MenuElements
//
- MenuElements.DropDownItems.AddRange(new ToolStripItem[] { MenuElementsColors, MenuElementsRemove });
+ MenuElements.DropDownItems.AddRange(new ToolStripItem[] { MenuElementsColors, MenuElementsDetail, MenuElementsRemove });
MenuElements.Name = "MenuElements";
- MenuElements.Size = new Size(67, 22);
+ MenuElements.Size = new Size(131, 38);
MenuElements.Text = "Elements";
//
// MenuElementsColors
//
MenuElementsColors.Name = "MenuElementsColors";
- MenuElementsColors.Size = new Size(117, 22);
+ MenuElementsColors.Size = new Size(359, 44);
MenuElementsColors.Text = "Colors";
//
// MenuElementsRemove
//
MenuElementsRemove.Name = "MenuElementsRemove";
- MenuElementsRemove.Size = new Size(117, 22);
+ MenuElementsRemove.Size = new Size(359, 44);
MenuElementsRemove.Text = "Remove";
//
// MenuOperations
//
MenuOperations.DropDownItems.AddRange(new ToolStripItem[] { MenuOperationsDerivative, MenuOperationsIntegral, MenuOperationsTranslate });
MenuOperations.Name = "MenuOperations";
- MenuOperations.Size = new Size(77, 22);
+ MenuOperations.Size = new Size(151, 38);
MenuOperations.Text = "Operations";
//
// MenuOperationsDerivative
//
MenuOperationsDerivative.Name = "MenuOperationsDerivative";
- MenuOperationsDerivative.Size = new Size(179, 22);
+ MenuOperationsDerivative.Size = new Size(360, 44);
MenuOperationsDerivative.Text = "Compute Derivative";
//
// MenuOperationsIntegral
//
MenuOperationsIntegral.Name = "MenuOperationsIntegral";
- MenuOperationsIntegral.Size = new Size(179, 22);
+ MenuOperationsIntegral.Size = new Size(360, 44);
MenuOperationsIntegral.Text = "Compute Integral";
//
// MenuOperationsTranslate
//
MenuOperationsTranslate.Name = "MenuOperationsTranslate";
- MenuOperationsTranslate.Size = new Size(179, 22);
+ MenuOperationsTranslate.Size = new Size(360, 44);
MenuOperationsTranslate.Text = "Translate";
//
// MenuConvert
//
MenuConvert.DropDownItems.AddRange(new ToolStripItem[] { MenuConvertEquation, MenuConvertSlopeField });
MenuConvert.Name = "MenuConvert";
- MenuConvert.Size = new Size(61, 22);
+ MenuConvert.Size = new Size(118, 38);
MenuConvert.Text = "Convert";
//
// MenuConvertEquation
//
MenuConvertEquation.Name = "MenuConvertEquation";
- MenuConvertEquation.Size = new Size(146, 22);
+ MenuConvertEquation.Size = new Size(297, 44);
MenuConvertEquation.Text = "To Equation";
//
// MenuConvertSlopeField
//
MenuConvertSlopeField.Name = "MenuConvertSlopeField";
- MenuConvertSlopeField.Size = new Size(146, 22);
+ MenuConvertSlopeField.Size = new Size(297, 44);
MenuConvertSlopeField.Text = "To Slope Field";
//
// MenuMisc
//
MenuMisc.DropDownItems.AddRange(new ToolStripItem[] { MenuMiscCaches, MiscMenuPreload });
MenuMisc.Name = "MenuMisc";
- MenuMisc.Size = new Size(44, 22);
+ MenuMisc.Size = new Size(83, 38);
MenuMisc.Text = "Misc";
//
// MenuMiscCaches
//
MenuMiscCaches.Name = "MenuMiscCaches";
- MenuMiscCaches.Size = new Size(150, 22);
+ MenuMiscCaches.Size = new Size(299, 44);
MenuMiscCaches.Text = "View Caches";
MenuMiscCaches.Click += MenuMiscCaches_Click;
//
// MiscMenuPreload
//
MiscMenuPreload.Name = "MiscMenuPreload";
- MiscMenuPreload.Size = new Size(150, 22);
+ MiscMenuPreload.Size = new Size(299, 44);
MiscMenuPreload.Text = "Preload Cache";
MiscMenuPreload.Click += MiscMenuPreload_Click;
//
@@ -210,18 +210,20 @@ namespace Graphing.Forms
UpdaterPopup.Controls.Add(UpdaterPopupDownloadButton);
UpdaterPopup.Controls.Add(UpdaterPopupCloseButton);
UpdaterPopup.Controls.Add(UpdaterPopupMessage);
- UpdaterPopup.Location = new Point(520, 371);
+ UpdaterPopup.Location = new Point(966, 791);
+ UpdaterPopup.Margin = new Padding(6, 6, 6, 6);
UpdaterPopup.Name = "UpdaterPopup";
- UpdaterPopup.Size = new Size(261, 55);
+ UpdaterPopup.Size = new Size(483, 115);
UpdaterPopup.TabIndex = 2;
UpdaterPopup.Visible = false;
//
// UpdaterPopupDownloadButton
//
UpdaterPopupDownloadButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right;
- UpdaterPopupDownloadButton.Location = new Point(181, 27);
+ UpdaterPopupDownloadButton.Location = new Point(336, 58);
+ UpdaterPopupDownloadButton.Margin = new Padding(6, 6, 6, 6);
UpdaterPopupDownloadButton.Name = "UpdaterPopupDownloadButton";
- UpdaterPopupDownloadButton.Size = new Size(75, 23);
+ UpdaterPopupDownloadButton.Size = new Size(139, 49);
UpdaterPopupDownloadButton.TabIndex = 2;
UpdaterPopupDownloadButton.Text = "Visit";
UpdaterPopupDownloadButton.UseVisualStyleBackColor = true;
@@ -229,10 +231,10 @@ namespace Graphing.Forms
// UpdaterPopupCloseButton
//
UpdaterPopupCloseButton.Anchor = AnchorStyles.Top | AnchorStyles.Right;
- UpdaterPopupCloseButton.Location = new Point(234, 1);
- UpdaterPopupCloseButton.Margin = new Padding(1);
+ UpdaterPopupCloseButton.Location = new Point(435, 2);
+ UpdaterPopupCloseButton.Margin = new Padding(2, 2, 2, 2);
UpdaterPopupCloseButton.Name = "UpdaterPopupCloseButton";
- UpdaterPopupCloseButton.Size = new Size(24, 24);
+ UpdaterPopupCloseButton.Size = new Size(45, 51);
UpdaterPopupCloseButton.TabIndex = 1;
UpdaterPopupCloseButton.Text = "X";
UpdaterPopupCloseButton.UseVisualStyleBackColor = true;
@@ -242,23 +244,29 @@ namespace Graphing.Forms
//
UpdaterPopupMessage.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
UpdaterPopupMessage.Font = new Font("Segoe UI", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 0);
- UpdaterPopupMessage.Location = new Point(3, 3);
- UpdaterPopupMessage.Margin = new Padding(3);
+ UpdaterPopupMessage.Location = new Point(6, 6);
+ UpdaterPopupMessage.Margin = new Padding(6, 6, 6, 6);
UpdaterPopupMessage.Name = "UpdaterPopupMessage";
- UpdaterPopupMessage.Size = new Size(228, 47);
+ UpdaterPopupMessage.Size = new Size(423, 100);
UpdaterPopupMessage.TabIndex = 0;
UpdaterPopupMessage.Text = "A update is available!\r\nA.B.C → E.F.G";
//
+ // MenuElementsDetail
+ //
+ MenuElementsDetail.Name = "MenuElementsDetail";
+ MenuElementsDetail.Size = new Size(359, 44);
+ MenuElementsDetail.Text = "Detail";
+ //
// GraphForm
//
- AutoScaleDimensions = new SizeF(7F, 15F);
+ AutoScaleDimensions = new SizeF(13F, 32F);
AutoScaleMode = AutoScaleMode.Font;
- ClientSize = new Size(780, 425);
+ ClientSize = new Size(1449, 907);
Controls.Add(UpdaterPopup);
Controls.Add(ResetViewportButton);
Controls.Add(GraphMenu);
MainMenuStrip = GraphMenu;
- Margin = new Padding(2, 1, 2, 1);
+ Margin = new Padding(4, 2, 4, 2);
Name = "GraphForm";
Text = "GraphFormBase";
GraphMenu.ResumeLayout(false);
@@ -294,5 +302,6 @@ namespace Graphing.Forms
private Label UpdaterPopupMessage;
private Button UpdaterPopupCloseButton;
private Button UpdaterPopupDownloadButton;
+ private ToolStripMenuItem MenuElementsDetail;
}
}
\ No newline at end of file
diff --git a/Base/Forms/GraphForm.cs b/Base/Forms/GraphForm.cs
index df116d7..4091d0f 100644
--- a/Base/Forms/GraphForm.cs
+++ b/Base/Forms/GraphForm.cs
@@ -1,4 +1,5 @@
using Graphing.Abstract;
+using Graphing.Graphables;
using System;
using System.Collections.Generic;
using System.Diagnostics;
@@ -444,9 +445,38 @@ public partial class GraphForm : Form
RegenerateMenuItems();
}
+ private readonly Dictionary sfDetailForms = [];
+ private void ChangeSlopeFieldDetail(SlopeField sf)
+ {
+ if (sfDetailForms.TryGetValue(sf, out SlopeFieldDetailForm? preexistingForm))
+ {
+ preexistingForm.Focus();
+ return;
+ }
+
+ SlopeFieldDetailForm detailForm = new(this, sf)
+ {
+ StartPosition = FormStartPosition.Manual
+ };
+ sfDetailForms.Add(sf, detailForm);
+
+ detailForm.Location = new Point(Location.X + ClientRectangle.Width + 10,
+ Location.Y + (ClientRectangle.Height - detailForm.ClientRectangle.Height) / 2);
+
+ if (detailForm.Location.X + detailForm.Width > Screen.FromControl(this).WorkingArea.Width)
+ {
+ detailForm.StartPosition = FormStartPosition.WindowsDefaultLocation;
+ }
+ detailForm.TopMost = true;
+ detailForm.Show();
+
+ detailForm.FormClosed += (o, e) => sfDetailForms.Remove(sf);
+ }
+
private void RegenerateMenuItems()
{
MenuElementsColors.DropDownItems.Clear();
+ MenuElementsDetail.DropDownItems.Clear();
MenuElementsRemove.DropDownItems.Clear();
MenuOperationsDerivative.DropDownItems.Clear();
MenuOperationsIntegral.DropDownItems.Clear();
@@ -474,6 +504,17 @@ public partial class GraphForm : Form
removeItem.Click += (o, e) => Ungraph(able);
MenuElementsRemove.DropDownItems.Add(removeItem);
+ if (able is SlopeField sf)
+ {
+ ToolStripMenuItem sfDetailItem = new()
+ {
+ ForeColor = able.Color,
+ Text = able.Name
+ };
+ sfDetailItem.Click += (o, e) => ChangeSlopeFieldDetail(sf);
+ MenuElementsDetail.DropDownItems.Add(sfDetailItem);
+ }
+
if (able is IDerivable derivable)
{
ToolStripMenuItem derivativeItem = new()
diff --git a/Base/Forms/SlopeFieldDetailForm.Designer.cs b/Base/Forms/SlopeFieldDetailForm.Designer.cs
new file mode 100644
index 0000000..1d93ed2
--- /dev/null
+++ b/Base/Forms/SlopeFieldDetailForm.Designer.cs
@@ -0,0 +1,147 @@
+namespace Graphing.Forms
+{
+ partial class SlopeFieldDetailForm
+ {
+ ///
+ /// 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()
+ {
+ Message = new System.Windows.Forms.Label();
+ TrackSlopeDetail = new System.Windows.Forms.TrackBar();
+ MinDetailBox = new System.Windows.Forms.TextBox();
+ MaxDetailBox = new System.Windows.Forms.TextBox();
+ CurrentDetailBox = new System.Windows.Forms.TextBox();
+ IncrementButton = new System.Windows.Forms.Button();
+ DecrementButton = new System.Windows.Forms.Button();
+ ((System.ComponentModel.ISupportInitialize)TrackSlopeDetail).BeginInit();
+ SuspendLayout();
+ //
+ // Message
+ //
+ Message.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ Message.Location = new System.Drawing.Point(119, 25);
+ Message.Margin = new System.Windows.Forms.Padding(110);
+ Message.Name = "Message";
+ Message.Size = new System.Drawing.Size(516, 109);
+ Message.TabIndex = 1;
+ Message.Text = "Change the Detail of %name%\r\nA higher value means more lines per unit.";
+ Message.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
+ //
+ // TrackSlopeDetail
+ //
+ TrackSlopeDetail.Anchor = System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
+ TrackSlopeDetail.LargeChange = 250;
+ TrackSlopeDetail.Location = new System.Drawing.Point(59, 158);
+ TrackSlopeDetail.Margin = new System.Windows.Forms.Padding(50);
+ TrackSlopeDetail.Maximum = 1000;
+ TrackSlopeDetail.Name = "TrackSlopeDetail";
+ TrackSlopeDetail.Size = new System.Drawing.Size(636, 90);
+ TrackSlopeDetail.SmallChange = 0;
+ TrackSlopeDetail.TabIndex = 0;
+ TrackSlopeDetail.TickFrequency = 0;
+ TrackSlopeDetail.TickStyle = System.Windows.Forms.TickStyle.Both;
+ TrackSlopeDetail.Scroll += TrackSlopeDetail_Scroll;
+ //
+ // MinDetailBox
+ //
+ MinDetailBox.Anchor = System.Windows.Forms.AnchorStyles.Left;
+ MinDetailBox.Location = new System.Drawing.Point(12, 228);
+ MinDetailBox.Name = "MinDetailBox";
+ MinDetailBox.Size = new System.Drawing.Size(100, 39);
+ MinDetailBox.TabIndex = 2;
+ //
+ // MaxDetailBox
+ //
+ MaxDetailBox.Anchor = System.Windows.Forms.AnchorStyles.Right;
+ MaxDetailBox.Location = new System.Drawing.Point(642, 228);
+ MaxDetailBox.Name = "MaxDetailBox";
+ MaxDetailBox.Size = new System.Drawing.Size(100, 39);
+ MaxDetailBox.TabIndex = 3;
+ MaxDetailBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Right;
+ //
+ // CurrentDetailBox
+ //
+ CurrentDetailBox.Anchor = System.Windows.Forms.AnchorStyles.None;
+ CurrentDetailBox.Location = new System.Drawing.Point(330, 228);
+ CurrentDetailBox.Name = "CurrentDetailBox";
+ CurrentDetailBox.Size = new System.Drawing.Size(100, 39);
+ CurrentDetailBox.TabIndex = 4;
+ CurrentDetailBox.TextAlign = System.Windows.Forms.HorizontalAlignment.Center;
+ //
+ // IncrementButton
+ //
+ IncrementButton.Anchor = System.Windows.Forms.AnchorStyles.None;
+ IncrementButton.Font = new System.Drawing.Font("Segoe UI", 7.875F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0);
+ IncrementButton.Location = new System.Drawing.Point(436, 228);
+ IncrementButton.Name = "IncrementButton";
+ IncrementButton.Size = new System.Drawing.Size(40, 40);
+ IncrementButton.TabIndex = 5;
+ IncrementButton.Text = "+";
+ IncrementButton.UseVisualStyleBackColor = true;
+ IncrementButton.Click += IncrementButton_Click;
+ //
+ // DecrementButton
+ //
+ DecrementButton.Anchor = System.Windows.Forms.AnchorStyles.None;
+ DecrementButton.Font = new System.Drawing.Font("Segoe UI", 7.875F, System.Drawing.FontStyle.Regular, System.Drawing.GraphicsUnit.Point, 0);
+ DecrementButton.Location = new System.Drawing.Point(284, 228);
+ DecrementButton.Name = "DecrementButton";
+ DecrementButton.Size = new System.Drawing.Size(40, 40);
+ DecrementButton.TabIndex = 6;
+ DecrementButton.Text = "-";
+ DecrementButton.UseVisualStyleBackColor = true;
+ DecrementButton.Click += DecrementButton_Click;
+ //
+ // SlopeFieldDetailForm
+ //
+ AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F);
+ AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
+ ClientSize = new System.Drawing.Size(754, 282);
+ Controls.Add(DecrementButton);
+ Controls.Add(IncrementButton);
+ Controls.Add(CurrentDetailBox);
+ Controls.Add(MaxDetailBox);
+ Controls.Add(MinDetailBox);
+ Controls.Add(Message);
+ Controls.Add(TrackSlopeDetail);
+ FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedToolWindow;
+ Name = "SlopeFieldDetailForm";
+ Text = "Change Slope Field Detail";
+ ((System.ComponentModel.ISupportInitialize)TrackSlopeDetail).EndInit();
+ ResumeLayout(false);
+ PerformLayout();
+ }
+
+ #endregion
+
+ private System.Windows.Forms.Label Message;
+ private System.Windows.Forms.TrackBar TrackSlopeDetail;
+ private System.Windows.Forms.TextBox MinDetailBox;
+ private System.Windows.Forms.TextBox MaxDetailBox;
+ private System.Windows.Forms.TextBox CurrentDetailBox;
+ private System.Windows.Forms.Button IncrementButton;
+ private System.Windows.Forms.Button DecrementButton;
+ }
+}
\ No newline at end of file
diff --git a/Base/Forms/SlopeFieldDetailForm.cs b/Base/Forms/SlopeFieldDetailForm.cs
new file mode 100644
index 0000000..20575c7
--- /dev/null
+++ b/Base/Forms/SlopeFieldDetailForm.cs
@@ -0,0 +1,130 @@
+using Graphing.Graphables;
+using System;
+using System.Windows.Forms;
+
+namespace Graphing.Forms;
+
+public partial class SlopeFieldDetailForm : Form
+{
+ private readonly GraphForm refForm;
+ private readonly SlopeField slopeField;
+
+ private double minDetail, maxDetail;
+
+ public SlopeFieldDetailForm(GraphForm form, SlopeField sf)
+ {
+ InitializeComponent();
+
+ refForm = form;
+ slopeField = sf;
+
+ refForm.Paint += (o, e) => RedeclareValues();
+ RedeclareValues();
+
+ TrackSlopeDetail.KeyDown += (o, e) =>
+ {
+ if (e.KeyCode == Keys.Right) IncrementButton_Click(o, e);
+ else if (e.KeyCode == Keys.Left) DecrementButton_Click(o, e);
+ };
+
+ MinDetailBox.Leave += MinDetailBox_Finish;
+ MinDetailBox.KeyDown += (o, e) =>
+ {
+ if (e.KeyCode == Keys.Enter) MinDetailBox_Finish(o, e);
+ };
+ MaxDetailBox.Leave += MaxDetailBox_Finish;
+ MaxDetailBox.KeyDown += (o, e) =>
+ {
+ if (e.KeyCode == Keys.Enter) MaxDetailBox_Finish(o, e);
+ };
+ CurrentDetailBox.Leave += CurrentDetailBox_Finish;
+ CurrentDetailBox.KeyDown += (o, e) =>
+ {
+ if (e.KeyCode == Keys.Enter) CurrentDetailBox_Finish(o, e);
+ };
+
+ minDetail = sf.Detail / 2;
+ maxDetail = sf.Detail * 2;
+
+ Message.Text = Message.Text.Replace("%name%", sf.Name);
+ }
+
+ // Exponential interpolations are better than simple lerps here since
+ // we're scaling a multiple rather than an additive.
+ private double Interp(double t)
+ {
+ // This is weird. I don't like the +1s and -1s, I don't think I wrote this right.
+ // But it seems to get the job done.
+ return minDetail + Math.Pow(2, t * Math.Log2(maxDetail - minDetail + 1)) - 1;
+ }
+ private double InverseInterp(double c)
+ {
+ return Math.Log2(c - minDetail + 1) / Math.Log2(maxDetail - minDetail + 1);
+ }
+
+ private void RedeclareValues()
+ {
+ double detail = slopeField.Detail;
+ if (detail < minDetail) minDetail = detail;
+ else if (detail > maxDetail) maxDetail = detail;
+
+ double t = InverseInterp(detail);
+ TrackSlopeDetail.Value = (int)(TrackSlopeDetail.Minimum + t * (TrackSlopeDetail.Maximum - TrackSlopeDetail.Minimum));
+
+ MinDetailBox.Text = $"{minDetail:0.00}";
+ MaxDetailBox.Text = $"{maxDetail:0.00}";
+ CurrentDetailBox.Text = $"{detail:0.00}";
+ }
+
+ private void TrackSlopeDetail_Scroll(object? sender, EventArgs e)
+ {
+ double t = (double)(TrackSlopeDetail.Value - TrackSlopeDetail.Minimum) / (TrackSlopeDetail.Maximum - TrackSlopeDetail.Minimum);
+ double newDetail = Interp(t);
+
+ slopeField.Detail = newDetail;
+ refForm.Invalidate(false);
+ }
+ private void MinDetailBox_Finish(object? sender, EventArgs e)
+ {
+ if (double.TryParse(MinDetailBox.Text, out double newMinDetail))
+ {
+ minDetail = newMinDetail;
+ if (minDetail > slopeField.Detail) slopeField.Detail = newMinDetail;
+ }
+ refForm.Invalidate(false);
+ }
+ private void MaxDetailBox_Finish(object? sender, EventArgs e)
+ {
+ if (double.TryParse(MaxDetailBox.Text, out double newMaxDetail))
+ {
+ maxDetail = newMaxDetail;
+ if (maxDetail < slopeField.Detail) slopeField.Detail = newMaxDetail;
+ }
+ refForm.Invalidate(false);
+ }
+ private void CurrentDetailBox_Finish(object? sender, EventArgs e)
+ {
+ if (double.TryParse(CurrentDetailBox.Text, out double newDetail))
+ {
+ if (newDetail < minDetail) minDetail = newDetail;
+ else if (newDetail > maxDetail) maxDetail = newDetail;
+ slopeField.Detail = newDetail;
+ }
+ refForm.Invalidate(false);
+ }
+
+ private void IncrementButton_Click(object? sender, EventArgs e)
+ {
+ double newDetail = slopeField.Detail * 1.0625f;
+ if (newDetail > maxDetail) maxDetail = newDetail;
+ slopeField.Detail = newDetail;
+ refForm.Invalidate(false);
+ }
+ private void DecrementButton_Click(object? sender, EventArgs e)
+ {
+ double newDetail = slopeField.Detail / 1.0625f;
+ if (newDetail < minDetail) minDetail = newDetail;
+ slopeField.Detail = newDetail;
+ refForm.Invalidate(false);
+ }
+}
diff --git a/Base/Forms/SlopeFieldDetailForm.resx b/Base/Forms/SlopeFieldDetailForm.resx
new file mode 100644
index 0000000..af32865
--- /dev/null
+++ b/Base/Forms/SlopeFieldDetailForm.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/SlopeField.cs b/Base/Graphables/SlopeField.cs
index 1ce56b9..44b877e 100644
--- a/Base/Graphables/SlopeField.cs
+++ b/Base/Graphables/SlopeField.cs
@@ -10,9 +10,24 @@ public class SlopeField : Graphable
{
private static int slopeFieldNum;
- protected readonly SlopeFieldsDelegate equ;
- protected readonly double detail;
+ public double Detail
+ {
+ get => _detail;
+ set
+ {
+ if (Math.Abs(value - Detail) >= 1e-4)
+ {
+ // When changing detail, we need to regenerate all
+ // the lines. Inefficient, I know. Might be optimized
+ // in a future update.
+ EraseCache();
+ }
+ _detail = value;
+ }
+ }
+ private double _detail;
+ protected readonly SlopeFieldsDelegate equ;
protected readonly List<(Float2, GraphLine)> cache;
public SlopeField(double detail, SlopeFieldsDelegate equ)
@@ -21,13 +36,13 @@ public class SlopeField : Graphable
Name = $"Slope Field {slopeFieldNum}";
this.equ = equ;
- this.detail = detail;
+ _detail = detail;
cache = [];
}
public override IEnumerable GetItemsToRender(in GraphForm graph)
{
- double step = 1 / detail;
+ double step = 1 / _detail;
double epsilon = step * 0.5;
List lines = [];
@@ -49,7 +64,7 @@ public class SlopeField : Graphable
protected GraphLine MakeSlopeLine(Float2 position, double slope)
{
- double size = detail;
+ double size = _detail;
double dirX = size, dirY = slope * size;
double magnitude = Math.Sqrt(dirX * dirX + dirY * dirY);
@@ -79,17 +94,17 @@ public class SlopeField : Graphable
return result;
}
- public override Graphable ShallowCopy() => new SlopeField(detail, equ);
+ public override Graphable ShallowCopy() => new SlopeField(_detail, equ);
public override void EraseCache() => cache.Clear();
public override long GetCacheBytes() => cache.Count * 48;
public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor)
{
- Float2 nearestPos = new(Math.Round(graphMousePos.x * detail) / detail,
- Math.Round(graphMousePos.y * detail) / detail);
+ Float2 nearestPos = new(Math.Round(graphMousePos.x * _detail) / _detail,
+ Math.Round(graphMousePos.y * _detail) / _detail);
- double epsilon = 1 / (detail * 2.0);
+ double epsilon = 1 / (_detail * 2.0);
GraphLine line = GetFromCache(epsilon, nearestPos.x, nearestPos.y);
double slope = (line.b.y - line.a.y) / (line.b.x - line.a.x);
@@ -110,10 +125,10 @@ public class SlopeField : Graphable
}
public override IEnumerable GetSelectionItemsToRender(in GraphForm graph, Float2 graphMousePos)
{
- Float2 nearestPos = new(Math.Round(graphMousePos.x * detail) / detail,
- Math.Round(graphMousePos.y * detail) / detail);
+ Float2 nearestPos = new(Math.Round(graphMousePos.x * _detail) / _detail,
+ Math.Round(graphMousePos.y * _detail) / _detail);
- double epsilon = 1 / (detail * 2.0);
+ double epsilon = 1 / (_detail * 2.0);
GraphLine line = GetFromCache(epsilon, nearestPos.x, nearestPos.y);
double slope = (line.b.y - line.a.y) / (line.b.x - line.a.x);
@@ -130,9 +145,9 @@ public class SlopeField : Graphable
public override void Preload(Float2 xRange, Float2 yRange, double step)
{
- for (double x = Math.Ceiling(xRange.x - 1); x < xRange.y + 1; x += 1.0 / detail)
+ for (double x = Math.Ceiling(xRange.x - 1); x < xRange.y + 1; x += 1.0 / _detail)
{
- for (double y = Math.Ceiling(yRange.x - 1); y < yRange.y + 1; y += 1.0 / detail)
+ for (double y = Math.Ceiling(yRange.x - 1); y < yRange.y + 1; y += 1.0 / _detail)
{
GetFromCache(step, x, y);
}
diff --git a/Testing/Program.cs b/Testing/Program.cs
index 87a07fa..35082d7 100644
--- a/Testing/Program.cs
+++ b/Testing/Program.cs
@@ -16,15 +16,12 @@ internal static class Program
GraphForm graph = new("One Of The Graphing Calculators Of All Time");
- /*Equation equA = new(Math.Sin),
+ Equation equA = new(Math.Sin),
equB = new(Math.Cos);
EquationDifference diff = new(2, equA, equB);
ParametricEquation equC = new(0, 20, t => 0.0375 * t * Math.Cos(t), t => 0.0625 * t * Math.Sin(t) + 3);
TangentLine tanA = new(2, 2, equA);
- graph.Graph(equA, equB, diff, equC, equB.ToColumnTable(-3, 3, 2), tanA);*/
-
- SlopeField sf1 = new(1.5, (x, y) => Math.Cos(x) + Math.Sin(y));
- graph.Graph(sf1);
+ graph.Graph(equA, equB, diff, equC, equB.ToColumnTable(-3, 3, 2), tanA);
Application.Run(graph);
}