From eea0bba3585b2545837f25057372ffdf77507251 Mon Sep 17 00:00:00 2001 From: That_One_Nerd Date: Mon, 29 Apr 2024 07:34:59 -0400 Subject: [PATCH] Slope field detail changer works. --- Base/Base.csproj.user | 3 + Base/Forms/GraphForm.Designer.cs | 83 ++++++----- Base/Forms/GraphForm.cs | 41 ++++++ Base/Forms/SlopeFieldDetailForm.Designer.cs | 147 ++++++++++++++++++++ Base/Forms/SlopeFieldDetailForm.cs | 130 +++++++++++++++++ Base/Forms/SlopeFieldDetailForm.resx | 120 ++++++++++++++++ Base/Graphables/SlopeField.cs | 43 ++++-- Testing/Program.cs | 7 +- 8 files changed, 518 insertions(+), 56 deletions(-) create mode 100644 Base/Forms/SlopeFieldDetailForm.Designer.cs create mode 100644 Base/Forms/SlopeFieldDetailForm.cs create mode 100644 Base/Forms/SlopeFieldDetailForm.resx 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); }