Slope field detail changer works.

This commit is contained in:
That_One_Nerd 2024-04-29 07:34:59 -04:00
parent 8b63bf011e
commit eea0bba358
8 changed files with 518 additions and 56 deletions

View File

@ -16,6 +16,9 @@
<Compile Update="Forms\SetZoomForm.cs"> <Compile Update="Forms\SetZoomForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>
<Compile Update="Forms\SlopeFieldDetailForm.cs">
<SubType>Form</SubType>
</Compile>
<Compile Update="Forms\TranslateForm.cs"> <Compile Update="Forms\TranslateForm.cs">
<SubType>Form</SubType> <SubType>Form</SubType>
</Compile> </Compile>

View File

@ -55,6 +55,7 @@ namespace Graphing.Forms
UpdaterPopupDownloadButton = new Button(); UpdaterPopupDownloadButton = new Button();
UpdaterPopupCloseButton = new Button(); UpdaterPopupCloseButton = new Button();
UpdaterPopupMessage = new Label(); UpdaterPopupMessage = new Label();
MenuElementsDetail = new ToolStripMenuItem();
GraphMenu.SuspendLayout(); GraphMenu.SuspendLayout();
UpdaterPopup.SuspendLayout(); UpdaterPopup.SuspendLayout();
SuspendLayout(); SuspendLayout();
@ -63,10 +64,10 @@ namespace Graphing.Forms
// //
ResetViewportButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; ResetViewportButton.Anchor = AnchorStyles.Top | AnchorStyles.Right;
ResetViewportButton.Font = new Font("Segoe UI Emoji", 12F, FontStyle.Regular, GraphicsUnit.Point, 0); ResetViewportButton.Font = new Font("Segoe UI Emoji", 12F, FontStyle.Regular, GraphicsUnit.Point, 0);
ResetViewportButton.Location = new Point(739, 20); ResetViewportButton.Location = new Point(1372, 43);
ResetViewportButton.Margin = new Padding(2, 1, 2, 1); ResetViewportButton.Margin = new Padding(4, 2, 4, 2);
ResetViewportButton.Name = "ResetViewportButton"; ResetViewportButton.Name = "ResetViewportButton";
ResetViewportButton.Size = new Size(34, 30); ResetViewportButton.Size = new Size(63, 64);
ResetViewportButton.TabIndex = 0; ResetViewportButton.TabIndex = 0;
ResetViewportButton.Text = "🏠"; ResetViewportButton.Text = "🏠";
ResetViewportButton.UseVisualStyleBackColor = true; ResetViewportButton.UseVisualStyleBackColor = true;
@ -78,8 +79,7 @@ namespace Graphing.Forms
GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuElements, MenuOperations, MenuConvert, MenuMisc }); GraphMenu.Items.AddRange(new ToolStripItem[] { MenuViewport, MenuElements, MenuOperations, MenuConvert, MenuMisc });
GraphMenu.Location = new Point(0, 0); GraphMenu.Location = new Point(0, 0);
GraphMenu.Name = "GraphMenu"; GraphMenu.Name = "GraphMenu";
GraphMenu.Padding = new Padding(3, 1, 0, 1); GraphMenu.Size = new Size(1449, 42);
GraphMenu.Size = new Size(780, 24);
GraphMenu.TabIndex = 1; GraphMenu.TabIndex = 1;
GraphMenu.Text = "menuStrip1"; GraphMenu.Text = "menuStrip1";
// //
@ -87,118 +87,118 @@ namespace Graphing.Forms
// //
MenuViewport.DropDownItems.AddRange(new ToolStripItem[] { ButtonViewportSetZoom, ButtonViewportSetCenter, ButtonViewportReset, ButtonViewportResetWindow }); MenuViewport.DropDownItems.AddRange(new ToolStripItem[] { ButtonViewportSetZoom, ButtonViewportSetCenter, ButtonViewportReset, ButtonViewportResetWindow });
MenuViewport.Name = "MenuViewport"; MenuViewport.Name = "MenuViewport";
MenuViewport.Size = new Size(66, 22); MenuViewport.Size = new Size(129, 38);
MenuViewport.Text = "Viewport"; MenuViewport.Text = "Viewport";
// //
// ButtonViewportSetZoom // ButtonViewportSetZoom
// //
ButtonViewportSetZoom.Name = "ButtonViewportSetZoom"; ButtonViewportSetZoom.Name = "ButtonViewportSetZoom";
ButtonViewportSetZoom.Size = new Size(174, 22); ButtonViewportSetZoom.Size = new Size(359, 44);
ButtonViewportSetZoom.Text = "Set Zoom"; ButtonViewportSetZoom.Text = "Set Zoom";
ButtonViewportSetZoom.Click += ButtonViewportSetZoom_Click; ButtonViewportSetZoom.Click += ButtonViewportSetZoom_Click;
// //
// ButtonViewportSetCenter // ButtonViewportSetCenter
// //
ButtonViewportSetCenter.Name = "ButtonViewportSetCenter"; ButtonViewportSetCenter.Name = "ButtonViewportSetCenter";
ButtonViewportSetCenter.Size = new Size(174, 22); ButtonViewportSetCenter.Size = new Size(359, 44);
ButtonViewportSetCenter.Text = "Set Center Position"; ButtonViewportSetCenter.Text = "Set Center Position";
ButtonViewportSetCenter.Click += ButtonViewportSetCenter_Click; ButtonViewportSetCenter.Click += ButtonViewportSetCenter_Click;
// //
// ButtonViewportReset // ButtonViewportReset
// //
ButtonViewportReset.Name = "ButtonViewportReset"; ButtonViewportReset.Name = "ButtonViewportReset";
ButtonViewportReset.Size = new Size(174, 22); ButtonViewportReset.Size = new Size(359, 44);
ButtonViewportReset.Text = "Reset Viewport"; ButtonViewportReset.Text = "Reset Viewport";
ButtonViewportReset.Click += ButtonViewportReset_Click; ButtonViewportReset.Click += ButtonViewportReset_Click;
// //
// ButtonViewportResetWindow // ButtonViewportResetWindow
// //
ButtonViewportResetWindow.Name = "ButtonViewportResetWindow"; ButtonViewportResetWindow.Name = "ButtonViewportResetWindow";
ButtonViewportResetWindow.Size = new Size(174, 22); ButtonViewportResetWindow.Size = new Size(359, 44);
ButtonViewportResetWindow.Text = "Reset Window Size"; ButtonViewportResetWindow.Text = "Reset Window Size";
ButtonViewportResetWindow.Click += ButtonViewportResetWindow_Click; ButtonViewportResetWindow.Click += ButtonViewportResetWindow_Click;
// //
// MenuElements // MenuElements
// //
MenuElements.DropDownItems.AddRange(new ToolStripItem[] { MenuElementsColors, MenuElementsRemove }); MenuElements.DropDownItems.AddRange(new ToolStripItem[] { MenuElementsColors, MenuElementsDetail, MenuElementsRemove });
MenuElements.Name = "MenuElements"; MenuElements.Name = "MenuElements";
MenuElements.Size = new Size(67, 22); MenuElements.Size = new Size(131, 38);
MenuElements.Text = "Elements"; MenuElements.Text = "Elements";
// //
// MenuElementsColors // MenuElementsColors
// //
MenuElementsColors.Name = "MenuElementsColors"; MenuElementsColors.Name = "MenuElementsColors";
MenuElementsColors.Size = new Size(117, 22); MenuElementsColors.Size = new Size(359, 44);
MenuElementsColors.Text = "Colors"; MenuElementsColors.Text = "Colors";
// //
// MenuElementsRemove // MenuElementsRemove
// //
MenuElementsRemove.Name = "MenuElementsRemove"; MenuElementsRemove.Name = "MenuElementsRemove";
MenuElementsRemove.Size = new Size(117, 22); MenuElementsRemove.Size = new Size(359, 44);
MenuElementsRemove.Text = "Remove"; MenuElementsRemove.Text = "Remove";
// //
// MenuOperations // MenuOperations
// //
MenuOperations.DropDownItems.AddRange(new ToolStripItem[] { MenuOperationsDerivative, MenuOperationsIntegral, MenuOperationsTranslate }); MenuOperations.DropDownItems.AddRange(new ToolStripItem[] { MenuOperationsDerivative, MenuOperationsIntegral, MenuOperationsTranslate });
MenuOperations.Name = "MenuOperations"; MenuOperations.Name = "MenuOperations";
MenuOperations.Size = new Size(77, 22); MenuOperations.Size = new Size(151, 38);
MenuOperations.Text = "Operations"; MenuOperations.Text = "Operations";
// //
// MenuOperationsDerivative // MenuOperationsDerivative
// //
MenuOperationsDerivative.Name = "MenuOperationsDerivative"; MenuOperationsDerivative.Name = "MenuOperationsDerivative";
MenuOperationsDerivative.Size = new Size(179, 22); MenuOperationsDerivative.Size = new Size(360, 44);
MenuOperationsDerivative.Text = "Compute Derivative"; MenuOperationsDerivative.Text = "Compute Derivative";
// //
// MenuOperationsIntegral // MenuOperationsIntegral
// //
MenuOperationsIntegral.Name = "MenuOperationsIntegral"; MenuOperationsIntegral.Name = "MenuOperationsIntegral";
MenuOperationsIntegral.Size = new Size(179, 22); MenuOperationsIntegral.Size = new Size(360, 44);
MenuOperationsIntegral.Text = "Compute Integral"; MenuOperationsIntegral.Text = "Compute Integral";
// //
// MenuOperationsTranslate // MenuOperationsTranslate
// //
MenuOperationsTranslate.Name = "MenuOperationsTranslate"; MenuOperationsTranslate.Name = "MenuOperationsTranslate";
MenuOperationsTranslate.Size = new Size(179, 22); MenuOperationsTranslate.Size = new Size(360, 44);
MenuOperationsTranslate.Text = "Translate"; MenuOperationsTranslate.Text = "Translate";
// //
// MenuConvert // MenuConvert
// //
MenuConvert.DropDownItems.AddRange(new ToolStripItem[] { MenuConvertEquation, MenuConvertSlopeField }); MenuConvert.DropDownItems.AddRange(new ToolStripItem[] { MenuConvertEquation, MenuConvertSlopeField });
MenuConvert.Name = "MenuConvert"; MenuConvert.Name = "MenuConvert";
MenuConvert.Size = new Size(61, 22); MenuConvert.Size = new Size(118, 38);
MenuConvert.Text = "Convert"; MenuConvert.Text = "Convert";
// //
// MenuConvertEquation // MenuConvertEquation
// //
MenuConvertEquation.Name = "MenuConvertEquation"; MenuConvertEquation.Name = "MenuConvertEquation";
MenuConvertEquation.Size = new Size(146, 22); MenuConvertEquation.Size = new Size(297, 44);
MenuConvertEquation.Text = "To Equation"; MenuConvertEquation.Text = "To Equation";
// //
// MenuConvertSlopeField // MenuConvertSlopeField
// //
MenuConvertSlopeField.Name = "MenuConvertSlopeField"; MenuConvertSlopeField.Name = "MenuConvertSlopeField";
MenuConvertSlopeField.Size = new Size(146, 22); MenuConvertSlopeField.Size = new Size(297, 44);
MenuConvertSlopeField.Text = "To Slope Field"; MenuConvertSlopeField.Text = "To Slope Field";
// //
// MenuMisc // MenuMisc
// //
MenuMisc.DropDownItems.AddRange(new ToolStripItem[] { MenuMiscCaches, MiscMenuPreload }); MenuMisc.DropDownItems.AddRange(new ToolStripItem[] { MenuMiscCaches, MiscMenuPreload });
MenuMisc.Name = "MenuMisc"; MenuMisc.Name = "MenuMisc";
MenuMisc.Size = new Size(44, 22); MenuMisc.Size = new Size(83, 38);
MenuMisc.Text = "Misc"; MenuMisc.Text = "Misc";
// //
// MenuMiscCaches // MenuMiscCaches
// //
MenuMiscCaches.Name = "MenuMiscCaches"; MenuMiscCaches.Name = "MenuMiscCaches";
MenuMiscCaches.Size = new Size(150, 22); MenuMiscCaches.Size = new Size(299, 44);
MenuMiscCaches.Text = "View Caches"; MenuMiscCaches.Text = "View Caches";
MenuMiscCaches.Click += MenuMiscCaches_Click; MenuMiscCaches.Click += MenuMiscCaches_Click;
// //
// MiscMenuPreload // MiscMenuPreload
// //
MiscMenuPreload.Name = "MiscMenuPreload"; MiscMenuPreload.Name = "MiscMenuPreload";
MiscMenuPreload.Size = new Size(150, 22); MiscMenuPreload.Size = new Size(299, 44);
MiscMenuPreload.Text = "Preload Cache"; MiscMenuPreload.Text = "Preload Cache";
MiscMenuPreload.Click += MiscMenuPreload_Click; MiscMenuPreload.Click += MiscMenuPreload_Click;
// //
@ -210,18 +210,20 @@ namespace Graphing.Forms
UpdaterPopup.Controls.Add(UpdaterPopupDownloadButton); UpdaterPopup.Controls.Add(UpdaterPopupDownloadButton);
UpdaterPopup.Controls.Add(UpdaterPopupCloseButton); UpdaterPopup.Controls.Add(UpdaterPopupCloseButton);
UpdaterPopup.Controls.Add(UpdaterPopupMessage); 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.Name = "UpdaterPopup";
UpdaterPopup.Size = new Size(261, 55); UpdaterPopup.Size = new Size(483, 115);
UpdaterPopup.TabIndex = 2; UpdaterPopup.TabIndex = 2;
UpdaterPopup.Visible = false; UpdaterPopup.Visible = false;
// //
// UpdaterPopupDownloadButton // UpdaterPopupDownloadButton
// //
UpdaterPopupDownloadButton.Anchor = AnchorStyles.Bottom | AnchorStyles.Right; 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.Name = "UpdaterPopupDownloadButton";
UpdaterPopupDownloadButton.Size = new Size(75, 23); UpdaterPopupDownloadButton.Size = new Size(139, 49);
UpdaterPopupDownloadButton.TabIndex = 2; UpdaterPopupDownloadButton.TabIndex = 2;
UpdaterPopupDownloadButton.Text = "Visit"; UpdaterPopupDownloadButton.Text = "Visit";
UpdaterPopupDownloadButton.UseVisualStyleBackColor = true; UpdaterPopupDownloadButton.UseVisualStyleBackColor = true;
@ -229,10 +231,10 @@ namespace Graphing.Forms
// UpdaterPopupCloseButton // UpdaterPopupCloseButton
// //
UpdaterPopupCloseButton.Anchor = AnchorStyles.Top | AnchorStyles.Right; UpdaterPopupCloseButton.Anchor = AnchorStyles.Top | AnchorStyles.Right;
UpdaterPopupCloseButton.Location = new Point(234, 1); UpdaterPopupCloseButton.Location = new Point(435, 2);
UpdaterPopupCloseButton.Margin = new Padding(1); UpdaterPopupCloseButton.Margin = new Padding(2, 2, 2, 2);
UpdaterPopupCloseButton.Name = "UpdaterPopupCloseButton"; UpdaterPopupCloseButton.Name = "UpdaterPopupCloseButton";
UpdaterPopupCloseButton.Size = new Size(24, 24); UpdaterPopupCloseButton.Size = new Size(45, 51);
UpdaterPopupCloseButton.TabIndex = 1; UpdaterPopupCloseButton.TabIndex = 1;
UpdaterPopupCloseButton.Text = "X"; UpdaterPopupCloseButton.Text = "X";
UpdaterPopupCloseButton.UseVisualStyleBackColor = true; UpdaterPopupCloseButton.UseVisualStyleBackColor = true;
@ -242,23 +244,29 @@ namespace Graphing.Forms
// //
UpdaterPopupMessage.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left; UpdaterPopupMessage.Anchor = AnchorStyles.Top | AnchorStyles.Bottom | AnchorStyles.Left;
UpdaterPopupMessage.Font = new Font("Segoe UI", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 0); UpdaterPopupMessage.Font = new Font("Segoe UI", 9.75F, FontStyle.Bold, GraphicsUnit.Point, 0);
UpdaterPopupMessage.Location = new Point(3, 3); UpdaterPopupMessage.Location = new Point(6, 6);
UpdaterPopupMessage.Margin = new Padding(3); UpdaterPopupMessage.Margin = new Padding(6, 6, 6, 6);
UpdaterPopupMessage.Name = "UpdaterPopupMessage"; UpdaterPopupMessage.Name = "UpdaterPopupMessage";
UpdaterPopupMessage.Size = new Size(228, 47); UpdaterPopupMessage.Size = new Size(423, 100);
UpdaterPopupMessage.TabIndex = 0; UpdaterPopupMessage.TabIndex = 0;
UpdaterPopupMessage.Text = "A <type> update is available!\r\nA.B.C → E.F.G"; UpdaterPopupMessage.Text = "A <type> update is available!\r\nA.B.C → E.F.G";
// //
// MenuElementsDetail
//
MenuElementsDetail.Name = "MenuElementsDetail";
MenuElementsDetail.Size = new Size(359, 44);
MenuElementsDetail.Text = "Detail";
//
// GraphForm // GraphForm
// //
AutoScaleDimensions = new SizeF(7F, 15F); AutoScaleDimensions = new SizeF(13F, 32F);
AutoScaleMode = AutoScaleMode.Font; AutoScaleMode = AutoScaleMode.Font;
ClientSize = new Size(780, 425); ClientSize = new Size(1449, 907);
Controls.Add(UpdaterPopup); Controls.Add(UpdaterPopup);
Controls.Add(ResetViewportButton); Controls.Add(ResetViewportButton);
Controls.Add(GraphMenu); Controls.Add(GraphMenu);
MainMenuStrip = GraphMenu; MainMenuStrip = GraphMenu;
Margin = new Padding(2, 1, 2, 1); Margin = new Padding(4, 2, 4, 2);
Name = "GraphForm"; Name = "GraphForm";
Text = "GraphFormBase"; Text = "GraphFormBase";
GraphMenu.ResumeLayout(false); GraphMenu.ResumeLayout(false);
@ -294,5 +302,6 @@ namespace Graphing.Forms
private Label UpdaterPopupMessage; private Label UpdaterPopupMessage;
private Button UpdaterPopupCloseButton; private Button UpdaterPopupCloseButton;
private Button UpdaterPopupDownloadButton; private Button UpdaterPopupDownloadButton;
private ToolStripMenuItem MenuElementsDetail;
} }
} }

View File

@ -1,4 +1,5 @@
using Graphing.Abstract; using Graphing.Abstract;
using Graphing.Graphables;
using System; using System;
using System.Collections.Generic; using System.Collections.Generic;
using System.Diagnostics; using System.Diagnostics;
@ -444,9 +445,38 @@ public partial class GraphForm : Form
RegenerateMenuItems(); RegenerateMenuItems();
} }
private readonly Dictionary<SlopeField, SlopeFieldDetailForm> 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() private void RegenerateMenuItems()
{ {
MenuElementsColors.DropDownItems.Clear(); MenuElementsColors.DropDownItems.Clear();
MenuElementsDetail.DropDownItems.Clear();
MenuElementsRemove.DropDownItems.Clear(); MenuElementsRemove.DropDownItems.Clear();
MenuOperationsDerivative.DropDownItems.Clear(); MenuOperationsDerivative.DropDownItems.Clear();
MenuOperationsIntegral.DropDownItems.Clear(); MenuOperationsIntegral.DropDownItems.Clear();
@ -474,6 +504,17 @@ public partial class GraphForm : Form
removeItem.Click += (o, e) => Ungraph(able); removeItem.Click += (o, e) => Ungraph(able);
MenuElementsRemove.DropDownItems.Add(removeItem); 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) if (able is IDerivable derivable)
{ {
ToolStripMenuItem derivativeItem = new() ToolStripMenuItem derivativeItem = new()

View File

@ -0,0 +1,147 @@
namespace Graphing.Forms
{
partial class SlopeFieldDetailForm
{
/// <summary>
/// Required designer variable.
/// </summary>
private System.ComponentModel.IContainer components = null;
/// <summary>
/// Clean up any resources being used.
/// </summary>
/// <param name="disposing">true if managed resources should be disposed; otherwise, false.</param>
protected override void Dispose(bool disposing)
{
if (disposing && (components != null))
{
components.Dispose();
}
base.Dispose(disposing);
}
#region Windows Form Designer generated code
/// <summary>
/// Required method for Designer support - do not modify
/// the contents of this method with the code editor.
/// </summary>
private void InitializeComponent()
{
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;
}
}

View File

@ -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);
}
}

View File

@ -0,0 +1,120 @@
<?xml version="1.0" encoding="utf-8"?>
<root>
<!--
Microsoft ResX Schema
Version 2.0
The primary goals of this format is to allow a simple XML format
that is mostly human readable. The generation and parsing of the
various data types are done through the TypeConverter classes
associated with the data types.
Example:
... ado.net/XML headers & schema ...
<resheader name="resmimetype">text/microsoft-resx</resheader>
<resheader name="version">2.0</resheader>
<resheader name="reader">System.Resources.ResXResourceReader, System.Windows.Forms, ...</resheader>
<resheader name="writer">System.Resources.ResXResourceWriter, System.Windows.Forms, ...</resheader>
<data name="Name1"><value>this is my long string</value><comment>this is a comment</comment></data>
<data name="Color1" type="System.Drawing.Color, System.Drawing">Blue</data>
<data name="Bitmap1" mimetype="application/x-microsoft.net.object.binary.base64">
<value>[base64 mime encoded serialized .NET Framework object]</value>
</data>
<data name="Icon1" type="System.Drawing.Icon, System.Drawing" mimetype="application/x-microsoft.net.object.bytearray.base64">
<value>[base64 mime encoded string representing a byte array form of the .NET Framework object]</value>
<comment>This is a comment</comment>
</data>
There are any number of "resheader" rows that contain simple
name/value pairs.
Each data row contains a name, and value. The row also contains a
type or mimetype. Type corresponds to a .NET class that support
text/value conversion through the TypeConverter architecture.
Classes that don't support this are serialized and stored with the
mimetype set.
The mimetype is used for serialized objects, and tells the
ResXResourceReader how to depersist the object. This is currently not
extensible. For a given mimetype the value must be set accordingly:
Note - application/x-microsoft.net.object.binary.base64 is the format
that the ResXResourceWriter will generate, however the reader can
read any of the formats listed below.
mimetype: application/x-microsoft.net.object.binary.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Binary.BinaryFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.soap.base64
value : The object must be serialized with
: System.Runtime.Serialization.Formatters.Soap.SoapFormatter
: and then encoded with base64 encoding.
mimetype: application/x-microsoft.net.object.bytearray.base64
value : The object must be serialized into a byte array
: using a System.ComponentModel.TypeConverter
: and then encoded with base64 encoding.
-->
<xsd:schema id="root" xmlns="" xmlns:xsd="http://www.w3.org/2001/XMLSchema" xmlns:msdata="urn:schemas-microsoft-com:xml-msdata">
<xsd:import namespace="http://www.w3.org/XML/1998/namespace" />
<xsd:element name="root" msdata:IsDataSet="true">
<xsd:complexType>
<xsd:choice maxOccurs="unbounded">
<xsd:element name="metadata">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" />
</xsd:sequence>
<xsd:attribute name="name" use="required" type="xsd:string" />
<xsd:attribute name="type" type="xsd:string" />
<xsd:attribute name="mimetype" type="xsd:string" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="assembly">
<xsd:complexType>
<xsd:attribute name="alias" type="xsd:string" />
<xsd:attribute name="name" type="xsd:string" />
</xsd:complexType>
</xsd:element>
<xsd:element name="data">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
<xsd:element name="comment" type="xsd:string" minOccurs="0" msdata:Ordinal="2" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" msdata:Ordinal="1" />
<xsd:attribute name="type" type="xsd:string" msdata:Ordinal="3" />
<xsd:attribute name="mimetype" type="xsd:string" msdata:Ordinal="4" />
<xsd:attribute ref="xml:space" />
</xsd:complexType>
</xsd:element>
<xsd:element name="resheader">
<xsd:complexType>
<xsd:sequence>
<xsd:element name="value" type="xsd:string" minOccurs="0" msdata:Ordinal="1" />
</xsd:sequence>
<xsd:attribute name="name" type="xsd:string" use="required" />
</xsd:complexType>
</xsd:element>
</xsd:choice>
</xsd:complexType>
</xsd:element>
</xsd:schema>
<resheader name="resmimetype">
<value>text/microsoft-resx</value>
</resheader>
<resheader name="version">
<value>2.0</value>
</resheader>
<resheader name="reader">
<value>System.Resources.ResXResourceReader, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
<resheader name="writer">
<value>System.Resources.ResXResourceWriter, System.Windows.Forms, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b77a5c561934e089</value>
</resheader>
</root>

View File

@ -10,9 +10,24 @@ public class SlopeField : Graphable
{ {
private static int slopeFieldNum; private static int slopeFieldNum;
protected readonly SlopeFieldsDelegate equ; public double Detail
protected readonly 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; protected readonly List<(Float2, GraphLine)> cache;
public SlopeField(double detail, SlopeFieldsDelegate equ) public SlopeField(double detail, SlopeFieldsDelegate equ)
@ -21,13 +36,13 @@ public class SlopeField : Graphable
Name = $"Slope Field {slopeFieldNum}"; Name = $"Slope Field {slopeFieldNum}";
this.equ = equ; this.equ = equ;
this.detail = detail; _detail = detail;
cache = []; cache = [];
} }
public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph) public override IEnumerable<IGraphPart> GetItemsToRender(in GraphForm graph)
{ {
double step = 1 / detail; double step = 1 / _detail;
double epsilon = step * 0.5; double epsilon = step * 0.5;
List<IGraphPart> lines = []; List<IGraphPart> lines = [];
@ -49,7 +64,7 @@ public class SlopeField : Graphable
protected GraphLine MakeSlopeLine(Float2 position, double slope) protected GraphLine MakeSlopeLine(Float2 position, double slope)
{ {
double size = detail; double size = _detail;
double dirX = size, dirY = slope * size; double dirX = size, dirY = slope * size;
double magnitude = Math.Sqrt(dirX * dirX + dirY * dirY); double magnitude = Math.Sqrt(dirX * dirX + dirY * dirY);
@ -79,17 +94,17 @@ public class SlopeField : Graphable
return result; 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 void EraseCache() => cache.Clear();
public override long GetCacheBytes() => cache.Count * 48; public override long GetCacheBytes() => cache.Count * 48;
public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor) public override bool ShouldSelectGraphable(in GraphForm graph, Float2 graphMousePos, double factor)
{ {
Float2 nearestPos = new(Math.Round(graphMousePos.x * detail) / detail, Float2 nearestPos = new(Math.Round(graphMousePos.x * _detail) / _detail,
Math.Round(graphMousePos.y * 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); GraphLine line = GetFromCache(epsilon, nearestPos.x, nearestPos.y);
double slope = (line.b.y - line.a.y) / (line.b.x - line.a.x); 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<IGraphPart> GetSelectionItemsToRender(in GraphForm graph, Float2 graphMousePos) public override IEnumerable<IGraphPart> GetSelectionItemsToRender(in GraphForm graph, Float2 graphMousePos)
{ {
Float2 nearestPos = new(Math.Round(graphMousePos.x * detail) / detail, Float2 nearestPos = new(Math.Round(graphMousePos.x * _detail) / _detail,
Math.Round(graphMousePos.y * 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); GraphLine line = GetFromCache(epsilon, nearestPos.x, nearestPos.y);
double slope = (line.b.y - line.a.y) / (line.b.x - line.a.x); 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) 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); GetFromCache(step, x, y);
} }

View File

@ -16,15 +16,12 @@ internal static class Program
GraphForm graph = new("One Of The Graphing Calculators Of All Time"); 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); equB = new(Math.Cos);
EquationDifference diff = new(2, equA, equB); 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); 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); TangentLine tanA = new(2, 2, equA);
graph.Graph(equA, equB, diff, equC, equB.ToColumnTable(-3, 3, 2), tanA);*/ 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);
Application.Run(graph); Application.Run(graph);
} }