Added a new project. Finished a while back.
This commit is contained in:
parent
4147a29fdc
commit
93f4ba647f
22
AirTrajectoryBuilder/AirTrajectoryBuilder.sln
Normal file
22
AirTrajectoryBuilder/AirTrajectoryBuilder.sln
Normal file
@ -0,0 +1,22 @@
|
||||
|
||||
Microsoft Visual Studio Solution File, Format Version 12.00
|
||||
# Visual Studio Version 17
|
||||
VisualStudioVersion = 17.12.35506.116 d17.12
|
||||
MinimumVisualStudioVersion = 10.0.40219.1
|
||||
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AirTrajectoryBuilder", "AirTrajectoryBuilder\AirTrajectoryBuilder.csproj", "{0EA33509-A4B2-4FB3-84E5-C9773FEDF0A9}"
|
||||
EndProject
|
||||
Global
|
||||
GlobalSection(SolutionConfigurationPlatforms) = preSolution
|
||||
Debug|Any CPU = Debug|Any CPU
|
||||
Release|Any CPU = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(ProjectConfigurationPlatforms) = postSolution
|
||||
{0EA33509-A4B2-4FB3-84E5-C9773FEDF0A9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
|
||||
{0EA33509-A4B2-4FB3-84E5-C9773FEDF0A9}.Debug|Any CPU.Build.0 = Debug|Any CPU
|
||||
{0EA33509-A4B2-4FB3-84E5-C9773FEDF0A9}.Release|Any CPU.ActiveCfg = Release|Any CPU
|
||||
{0EA33509-A4B2-4FB3-84E5-C9773FEDF0A9}.Release|Any CPU.Build.0 = Release|Any CPU
|
||||
EndGlobalSection
|
||||
GlobalSection(SolutionProperties) = preSolution
|
||||
HideSolutionNode = FALSE
|
||||
EndGlobalSection
|
||||
EndGlobal
|
||||
BIN
AirTrajectoryBuilder/AirTrajectoryBuilder.zip
Normal file
BIN
AirTrajectoryBuilder/AirTrajectoryBuilder.zip
Normal file
Binary file not shown.
@ -0,0 +1,15 @@
|
||||
<Project Sdk="Microsoft.NET.Sdk">
|
||||
|
||||
<PropertyGroup>
|
||||
<OutputType>WinExe</OutputType>
|
||||
<TargetFramework>net9.0-windows</TargetFramework>
|
||||
<Nullable>enable</Nullable>
|
||||
<UseWindowsForms>true</UseWindowsForms>
|
||||
<ImplicitUsings>disable</ImplicitUsings>
|
||||
</PropertyGroup>
|
||||
|
||||
<ItemGroup>
|
||||
<PackageReference Include="Nerd_STF" Version="3.0.0-beta1" />
|
||||
</ItemGroup>
|
||||
|
||||
</Project>
|
||||
@ -0,0 +1,17 @@
|
||||
<?xml version="1.0" encoding="utf-8"?>
|
||||
<Project ToolsVersion="Current" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
|
||||
<ItemGroup>
|
||||
<Compile Update="Forms\MainForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\SweepCancelForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\SweepInfoViewer.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
<Compile Update="Forms\SweepParametersForm.cs">
|
||||
<SubType>Form</SubType>
|
||||
</Compile>
|
||||
</ItemGroup>
|
||||
</Project>
|
||||
127
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/MainForm.Designer.cs
generated
Normal file
127
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/MainForm.Designer.cs
generated
Normal file
@ -0,0 +1,127 @@
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AirTrajectoryBuilder
|
||||
{
|
||||
partial class MainForm
|
||||
{
|
||||
/// <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()
|
||||
{
|
||||
Menu = new MenuStrip();
|
||||
MenuFile = new ToolStripMenuItem();
|
||||
MenuFileNew = new ToolStripMenuItem();
|
||||
MenuFileOpen = new ToolStripMenuItem();
|
||||
MenuRun = new ToolStripMenuItem();
|
||||
MenuRunSweep = new ToolStripMenuItem();
|
||||
FileOpener = new OpenFileDialog();
|
||||
MenuRunCancel = new ToolStripMenuItem();
|
||||
Menu.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// Menu
|
||||
//
|
||||
Menu.ImageScalingSize = new Size(32, 32);
|
||||
Menu.Items.AddRange(new ToolStripItem[] { MenuFile, MenuRun });
|
||||
Menu.Location = new Point(0, 0);
|
||||
Menu.Name = "Menu";
|
||||
Menu.Size = new Size(1263, 42);
|
||||
Menu.TabIndex = 0;
|
||||
Menu.Text = "menuStrip1";
|
||||
//
|
||||
// MenuFile
|
||||
//
|
||||
MenuFile.DropDownItems.AddRange(new ToolStripItem[] { MenuFileNew, MenuFileOpen });
|
||||
MenuFile.Name = "MenuFile";
|
||||
MenuFile.Size = new Size(71, 38);
|
||||
MenuFile.Text = "File";
|
||||
//
|
||||
// MenuFileNew
|
||||
//
|
||||
MenuFileNew.Name = "MenuFileNew";
|
||||
MenuFileNew.Size = new Size(221, 44);
|
||||
MenuFileNew.Text = "New";
|
||||
MenuFileNew.Click += MenuFileNew_Click;
|
||||
//
|
||||
// MenuFileOpen
|
||||
//
|
||||
MenuFileOpen.Name = "MenuFileOpen";
|
||||
MenuFileOpen.Size = new Size(221, 44);
|
||||
MenuFileOpen.Text = "Open...";
|
||||
MenuFileOpen.Click += MenuFileOpen_Click;
|
||||
//
|
||||
// MenuRun
|
||||
//
|
||||
MenuRun.DropDownItems.AddRange(new ToolStripItem[] { MenuRunSweep, MenuRunCancel });
|
||||
MenuRun.Name = "MenuRun";
|
||||
MenuRun.Size = new Size(76, 38);
|
||||
MenuRun.Text = "Run";
|
||||
//
|
||||
// MenuRunSweep
|
||||
//
|
||||
MenuRunSweep.Name = "MenuRunSweep";
|
||||
MenuRunSweep.Size = new Size(359, 44);
|
||||
MenuRunSweep.Text = "Sweep...";
|
||||
MenuRunSweep.Click += MenuRunSweep_Click;
|
||||
//
|
||||
// FileOpener
|
||||
//
|
||||
FileOpener.Filter = "Scene files|*.sce|All files|*.*";
|
||||
//
|
||||
// MenuRunCancel
|
||||
//
|
||||
MenuRunCancel.Name = "MenuRunCancel";
|
||||
MenuRunCancel.Size = new Size(359, 44);
|
||||
MenuRunCancel.Text = "Cancel";
|
||||
MenuRunCancel.Click += MenuRunCancel_Click;
|
||||
//
|
||||
// MainForm
|
||||
//
|
||||
AutoScaleDimensions = new SizeF(13F, 32F);
|
||||
AutoScaleMode = AutoScaleMode.Font;
|
||||
ClientSize = new Size(1263, 719);
|
||||
Controls.Add(Menu);
|
||||
MainMenuStrip = Menu;
|
||||
Name = "MainForm";
|
||||
Text = "MainForm";
|
||||
Menu.ResumeLayout(false);
|
||||
Menu.PerformLayout();
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private MenuStrip Menu;
|
||||
private ToolStripMenuItem MenuFile;
|
||||
private ToolStripMenuItem MenuFileOpen;
|
||||
private ToolStripMenuItem MenuFileNew;
|
||||
private OpenFileDialog FileOpener;
|
||||
private ToolStripMenuItem MenuRun;
|
||||
private ToolStripMenuItem MenuRunSweep;
|
||||
private ToolStripMenuItem MenuRunCancel;
|
||||
}
|
||||
}
|
||||
447
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/MainForm.cs
Normal file
447
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/MainForm.cs
Normal file
@ -0,0 +1,447 @@
|
||||
using AirTrajectoryBuilder.ObjectModels;
|
||||
using System.Windows.Forms;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System;
|
||||
using Nerd_STF.Mathematics;
|
||||
using System.IO;
|
||||
using System.Reflection;
|
||||
using System.Drawing.Drawing2D;
|
||||
using System.Threading.Tasks;
|
||||
using System.Threading;
|
||||
using AirTrajectoryBuilder.Forms;
|
||||
|
||||
namespace AirTrajectoryBuilder;
|
||||
|
||||
public partial class MainForm : Form
|
||||
{
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public Scene Scene { get; set; }
|
||||
|
||||
private readonly float scalingFactor;
|
||||
private readonly string baseFolder, sceneFolder;
|
||||
|
||||
public SweepParameters? SweepParameters;
|
||||
|
||||
private CancellationTokenSource? simCancel;
|
||||
private SimulationResult? simResult;
|
||||
private SweepStatus simStatus;
|
||||
private SweepCancelForm? simCancelForm;
|
||||
internal SweepInfoViewer? simViewer;
|
||||
|
||||
private readonly Font statusFont;
|
||||
|
||||
public MainForm(Scene? initialScene)
|
||||
{
|
||||
InitializeComponent();
|
||||
|
||||
SetStyle(ControlStyles.UserPaint, true);
|
||||
SetStyle(ControlStyles.AllPaintingInWmPaint, true);
|
||||
SetStyle(ControlStyles.OptimizedDoubleBuffer, true);
|
||||
|
||||
Graphics tempG = CreateGraphics();
|
||||
scalingFactor = tempG.DpiX / 96;
|
||||
tempG.Dispose();
|
||||
|
||||
baseFolder = Path.GetDirectoryName(Assembly.GetExecutingAssembly().Location)!;
|
||||
sceneFolder = Path.Combine(baseFolder, "./scenes/");
|
||||
Directory.CreateDirectory(sceneFolder);
|
||||
FileOpener.InitialDirectory = sceneFolder;
|
||||
|
||||
Scene = initialScene ?? Scene.Default;
|
||||
|
||||
statusFont = new("Segoe UI", 10);
|
||||
MenuRunCancel.Enabled = false;
|
||||
}
|
||||
|
||||
public Int2 PlotToScreen(Float2 plot)
|
||||
{
|
||||
int menuHeight = Menu.Height;
|
||||
int buffer = (int)(20 * scalingFactor);
|
||||
|
||||
double bufferX, bufferY, maxPix, pixPerUnit;
|
||||
double clientAspect = (double)(ClientRectangle.Height - menuHeight - buffer * 2) / (ClientRectangle.Width - buffer * 2),
|
||||
sceneAspect = Scene.Height / Scene.Width;
|
||||
|
||||
if (clientAspect > sceneAspect)
|
||||
{
|
||||
// Client is taller than scene, use width as max.
|
||||
maxPix = ClientRectangle.Width - 2 * buffer;
|
||||
pixPerUnit = maxPix / Scene.Width;
|
||||
|
||||
bufferX = buffer;
|
||||
bufferY = (ClientRectangle.Height + menuHeight - Scene.Height * pixPerUnit) * 0.5f;
|
||||
}
|
||||
else
|
||||
{
|
||||
// Client is wider than scene, use height as max.
|
||||
maxPix = ClientRectangle.Height - menuHeight - 2 * buffer;
|
||||
pixPerUnit = maxPix / Scene.Height;
|
||||
|
||||
bufferX = (ClientRectangle.Width - Scene.Width * pixPerUnit) * 0.5f;
|
||||
bufferY = buffer + menuHeight;
|
||||
}
|
||||
|
||||
return ((int)(plot.x * pixPerUnit + bufferX),
|
||||
(int)((Scene.Height - plot.y) * pixPerUnit + bufferY));
|
||||
}
|
||||
|
||||
protected override void OnPaint(PaintEventArgs e)
|
||||
{
|
||||
Graphics g = e.Graphics;
|
||||
g.SmoothingMode = SmoothingMode.HighQuality;
|
||||
Pen pen = new(Color.Black, scalingFactor);
|
||||
SolidBrush fill = new(Color.Black);
|
||||
|
||||
const int fillAlpha = 64;
|
||||
|
||||
// Draw components.
|
||||
foreach (ISceneObject obj in Scene.Objects)
|
||||
{
|
||||
if (obj is SceneRect objRect)
|
||||
{
|
||||
pen.Color = Color.Green;
|
||||
fill.Color = Color.FromArgb(fillAlpha, pen.Color);
|
||||
Int2 rectFrom = PlotToScreen(objRect.From), rectTo = PlotToScreen(objRect.To);
|
||||
int minX = int.Min(rectFrom.x, rectTo.x), sizeX = MathE.Absolute(rectFrom.x - rectTo.x),
|
||||
minY = int.Min(rectFrom.y, rectTo.y), sizeY = MathE.Absolute(rectFrom.y - rectTo.y);
|
||||
Rectangle rect = new(new Point(minX, minY), new Size(sizeX, sizeY));
|
||||
g.FillRectangle(fill, rect);
|
||||
g.DrawRectangle(pen, rect);
|
||||
}
|
||||
else if (obj is SceneTri objTri)
|
||||
{
|
||||
pen.Color = Color.Orange;
|
||||
fill.Color = Color.FromArgb(fillAlpha, pen.Color);
|
||||
Int2 triA = PlotToScreen(objTri.A),
|
||||
triB = PlotToScreen(objTri.B),
|
||||
triC = PlotToScreen(objTri.C);
|
||||
g.FillPolygon(fill, [triA, triB, triC]);
|
||||
g.DrawPolygon(pen, [triA, triB, triC]);
|
||||
}
|
||||
else if (obj is SceneEllipse objEllipse)
|
||||
{
|
||||
pen.Color = Color.Purple;
|
||||
fill.Color = Color.FromArgb(fillAlpha, pen.Color);
|
||||
Int2 min = PlotToScreen(objEllipse.Position - objEllipse.Size * 0.5),
|
||||
max = PlotToScreen(objEllipse.Position + objEllipse.Size * 0.5);
|
||||
Rectangle ellipseRect = new(min, max - min);
|
||||
g.FillEllipse(fill, ellipseRect);
|
||||
g.DrawEllipse(pen, ellipseRect);
|
||||
}
|
||||
}
|
||||
|
||||
// Draw scene border.
|
||||
pen.Color = Color.Blue;
|
||||
pen.Width = scalingFactor * 2;
|
||||
Int2 sceneMin = PlotToScreen((0, Scene.Height)), sceneMax = PlotToScreen((Scene.Width, 0));
|
||||
g.DrawRectangle(pen, new Rectangle(sceneMin, sceneMax - sceneMin));
|
||||
|
||||
// Draw starting position.
|
||||
int startPosSize = (int)(6 * scalingFactor);
|
||||
pen.Color = Color.Red;
|
||||
pen.Width = scalingFactor;
|
||||
fill.Color = Color.FromArgb(fillAlpha, pen.Color);
|
||||
Int2 startPos = PlotToScreen(Scene.StartAt);
|
||||
startPos.x -= startPosSize;
|
||||
startPos.y -= startPosSize;
|
||||
Rectangle startRect = new(startPos, Int2.One * startPosSize * 2);
|
||||
g.FillEllipse(fill, startRect);
|
||||
g.DrawEllipse(pen, startRect);
|
||||
|
||||
// Draw ending position.
|
||||
pen.Color = Color.Lime;
|
||||
pen.Width = scalingFactor;
|
||||
fill.Color = Color.FromArgb(fillAlpha, pen.Color);
|
||||
Int2 endPos = PlotToScreen(Scene.EndAt);
|
||||
endPos.x -= startPosSize;
|
||||
endPos.y -= startPosSize;
|
||||
Rectangle endRect = new(endPos, Int2.One * startPosSize * 2);
|
||||
g.FillEllipse(fill, endRect);
|
||||
g.DrawEllipse(pen, endRect);
|
||||
|
||||
// If there's a trail, draw it.
|
||||
pen.Color = Color.Red;
|
||||
if (simResult is not null)
|
||||
{
|
||||
Point[] points = new Point[simResult.Trail.Count];
|
||||
for (int i = 0; i < points.Length; i++)
|
||||
{
|
||||
points[i] = PlotToScreen(simResult.Trail[i]);
|
||||
}
|
||||
g.DrawLines(pen, points);
|
||||
|
||||
// Draw X at end point (if it's a crash and not a finish).
|
||||
if (simResult.EndDistanceSquared >= SweepParameters!.Tolerance * SweepParameters.Tolerance)
|
||||
{
|
||||
Int2 end = points[^1];
|
||||
PointF[] xShape = [
|
||||
new Float2(-5, -5) * scalingFactor + end,
|
||||
new Float2(5, 5) * scalingFactor + end,
|
||||
new Float2(0, 0) * scalingFactor + end,
|
||||
new Float2(-5, 5) * scalingFactor + end,
|
||||
new Float2(5, -5) * scalingFactor + end,
|
||||
];
|
||||
g.DrawLines(pen, xShape);
|
||||
}
|
||||
}
|
||||
|
||||
string message = simStatus switch
|
||||
{
|
||||
SweepStatus.NoSweep => "No Sweep",
|
||||
SweepStatus.Sweeping => $"Sweeping... Best {simResult?.StartingConditions.StartAngle:0.000} deg, {simResult?.StartingConditions.StartVelocity:0.0} m/s",
|
||||
SweepStatus.FinishedSweep => $"Done Sweeping. Best {simResult?.StartingConditions.StartAngle:0.000} deg, {simResult?.StartingConditions.StartVelocity:0.0} m/s",
|
||||
SweepStatus.CancelledSweep => $"Cancelled Sweep. Best {simResult?.StartingConditions.StartAngle:0.000} deg, {simResult?.StartingConditions.StartVelocity:0.0} m/s",
|
||||
_ => "???",
|
||||
};
|
||||
fill.Color = Color.Blue;
|
||||
SizeF size = g.MeasureString(message, statusFont);
|
||||
const float spacing = 1;
|
||||
g.DrawString(message, statusFont, fill, new PointF(spacing * scalingFactor, ClientRectangle.Height - size.Height - spacing * scalingFactor));
|
||||
|
||||
e.Dispose();
|
||||
}
|
||||
protected override void OnClientSizeChanged(EventArgs e)
|
||||
{
|
||||
base.OnClientSizeChanged(e);
|
||||
Invalidate(true);
|
||||
}
|
||||
|
||||
private void ResetSceneData()
|
||||
{
|
||||
simCancel?.Cancel();
|
||||
|
||||
simResult = null;
|
||||
simCancel = null;
|
||||
SweepParameters = null;
|
||||
simStatus = SweepStatus.NoSweep;
|
||||
simViewer?.Close();
|
||||
Invalidate(true);
|
||||
}
|
||||
|
||||
private void MenuFileNew_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!TryCancelSweep()) return;
|
||||
|
||||
if (!Scene.HasBeenSaved)
|
||||
{
|
||||
DialogResult result = MessageBox.Show(
|
||||
"Are you sure you want to discard your changes?", "Lose changes?",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||
|
||||
if (result == DialogResult.No) return;
|
||||
}
|
||||
Scene = Scene.Default;
|
||||
ResetSceneData();
|
||||
}
|
||||
private void MenuFileOpen_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!TryCancelSweep()) return;
|
||||
|
||||
DialogResult result;
|
||||
if (!Scene.HasBeenSaved)
|
||||
{
|
||||
result = MessageBox.Show(
|
||||
"Are you sure you want to discard your changes?", "Lose changes?",
|
||||
MessageBoxButtons.YesNo, MessageBoxIcon.Warning);
|
||||
|
||||
if (result == DialogResult.No) return;
|
||||
}
|
||||
result = FileOpener.ShowDialog();
|
||||
if (result == DialogResult.Cancel) return;
|
||||
|
||||
try
|
||||
{
|
||||
Scene = Scene.Read(FileOpener.FileName);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error opening scene file: {ex.GetType().Name}");
|
||||
}
|
||||
ResetSceneData();
|
||||
}
|
||||
|
||||
private void MenuRunSweep_Click(object? sender, EventArgs e)
|
||||
{
|
||||
if (!TryCancelSweep()) return;
|
||||
|
||||
SweepParametersForm param = new(this);
|
||||
DialogResult result = param.ShowDialog();
|
||||
if (result == DialogResult.Cancel) return;
|
||||
|
||||
SweepParameters = param.Result;
|
||||
simCancel = new();
|
||||
simStatus = SweepStatus.Sweeping;
|
||||
MenuRunCancel.Enabled = true;
|
||||
simViewer ??= new SweepInfoViewer(this);
|
||||
simViewer.UncompleteSweep();
|
||||
simViewer.Show();
|
||||
Task.Run(() => SweepSimulation(SweepParameters, simCancel.Token));
|
||||
}
|
||||
|
||||
public bool TryCancelSweep()
|
||||
{
|
||||
if (simStatus == SweepStatus.Sweeping && simCancel is not null)
|
||||
{
|
||||
SweepCancelForm form = new();
|
||||
simCancelForm = form;
|
||||
DialogResult result = form.ShowDialog();
|
||||
if (result == DialogResult.No) return false;
|
||||
|
||||
simCancel?.Cancel();
|
||||
return true;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
private void SweepSimulation(SweepParameters param, CancellationToken token)
|
||||
{
|
||||
Float2 diff = param.Scene.EndAt - param.Scene.StartAt;
|
||||
double minAngle = Math.Atan2(diff.y, diff.x) * Constants.Pi / 180,
|
||||
maxAngle = Constants.Pi / 2,
|
||||
angleStep = param.AngleDelta * Constants.Pi / 180;
|
||||
|
||||
double closest = double.MaxValue, tolSquared = param.Tolerance * param.Tolerance;
|
||||
bool end = false;
|
||||
int angleSteps = (int)((maxAngle - minAngle) / angleStep);
|
||||
int steps = 0;
|
||||
simViewer?.SetMaxIters(angleSteps);
|
||||
for (double ang = minAngle; ang <= maxAngle; ang += angleStep)
|
||||
{
|
||||
for (double vel = param.SpeedMin; vel <= param.SpeedMax; vel += param.SpeedDelta)
|
||||
{
|
||||
if (token.IsCancellationRequested)
|
||||
{
|
||||
end = true;
|
||||
break;
|
||||
}
|
||||
SimulationParameters simParams = new()
|
||||
{
|
||||
DeltaTime = param.TimeDelta,
|
||||
Gravity = param.Gravity,
|
||||
StartAngle = ang,
|
||||
StartVelocity = vel,
|
||||
Scene = Scene,
|
||||
ToleranceSquared = tolSquared,
|
||||
ObjectRadius = param.ObjectRadius,
|
||||
DragCoefficient = param.DragCoefficient,
|
||||
Mass = param.Mass,
|
||||
AirDensity = param.AirDensity,
|
||||
GenerateTable = param.FileMode != ResultsFileMode.None
|
||||
};
|
||||
SimulationResult result = SimulateTrajectory(simParams, token);
|
||||
if (result.EndDistanceSquared < closest)
|
||||
{
|
||||
Invoke(() =>
|
||||
{
|
||||
simResult = result;
|
||||
});
|
||||
Invalidate(true);
|
||||
closest = result.EndDistanceSquared;
|
||||
}
|
||||
}
|
||||
if (end) break;
|
||||
simViewer?.SetCurrentIters(steps);
|
||||
steps++;
|
||||
}
|
||||
simCancel = null;
|
||||
simStatus = token.IsCancellationRequested ? SweepStatus.CancelledSweep : SweepStatus.FinishedSweep;
|
||||
if (simCancelForm is not null)
|
||||
{
|
||||
simCancelForm.DialogResult = DialogResult.No;
|
||||
simCancelForm.Close();
|
||||
}
|
||||
MenuRunCancel.Enabled = false;
|
||||
simViewer?.Invoke(() => simViewer?.CompleteSweep(simResult!));
|
||||
Invalidate(true);
|
||||
}
|
||||
private static SimulationResult SimulateTrajectory(SimulationParameters param, CancellationToken token)
|
||||
{
|
||||
Float2 pos = param.Scene.StartAt;
|
||||
Float2 vel = (Math.Cos(param.StartAngle) * param.StartVelocity,
|
||||
Math.Sin(param.StartAngle) * param.StartVelocity);
|
||||
Float2 gravity = (0, param.Gravity);
|
||||
double halfArea = 0.5 * param.ObjectRadius * param.ObjectRadius * Constants.Pi;
|
||||
|
||||
SimulationResult result = new(param);
|
||||
double trailPointsPerSecond = 5;
|
||||
int ticksPerTrailPoint = (int)(1 / (trailPointsPerSecond * param.DeltaTime));
|
||||
|
||||
if (param.GenerateTable) result.Table = [];
|
||||
|
||||
int ticks = 0;
|
||||
double time = 0;
|
||||
while (true)
|
||||
{
|
||||
Float2 air = (halfArea * param.DragCoefficient * param.AirDensity * vel.x * vel.x,
|
||||
halfArea * param.DragCoefficient * param.AirDensity * vel.y * vel.y);
|
||||
|
||||
Float2 acc = gravity;
|
||||
if (param.Mass > 0)
|
||||
{
|
||||
air /= param.Mass;
|
||||
acc.x -= air.x * Math.Sign(vel.x);
|
||||
acc.y -= air.y * Math.Sign(vel.y);
|
||||
}
|
||||
|
||||
if (param.GenerateTable) result.Table!.Add(new(pos, vel, acc));
|
||||
|
||||
if (pos.x < 0 || pos.x >= param.Scene.Width ||
|
||||
pos.y < 0 || pos.y >= param.Scene.Height)
|
||||
{
|
||||
result.Trail.Add(pos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (token.IsCancellationRequested) break;
|
||||
|
||||
bool collide = false;
|
||||
for (int i = 0; i < param.Scene.Objects.Count; i++)
|
||||
{
|
||||
if (param.Scene.Objects[i].Contains(pos))
|
||||
{
|
||||
collide = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (collide)
|
||||
{
|
||||
result.Trail.Add(pos);
|
||||
break;
|
||||
}
|
||||
|
||||
Float2 diff = param.Scene.EndAt - pos;
|
||||
result.EndDistanceSquared = diff.x * diff.x + diff.y * diff.y;
|
||||
if (result.EndDistanceSquared <= param.ToleranceSquared)
|
||||
{
|
||||
result.Trail.Add(pos);
|
||||
break;
|
||||
}
|
||||
|
||||
if (ticks % ticksPerTrailPoint == 0) result.Trail.Add(pos);
|
||||
|
||||
pos += vel * param.DeltaTime;
|
||||
vel += acc * param.DeltaTime;
|
||||
|
||||
time += param.DeltaTime;
|
||||
}
|
||||
result.StartingConditions.StartAngle *= 180 / Constants.Pi;
|
||||
result.EndSpeed = vel.Magnitude;
|
||||
result.Duration = time;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
private void MenuRunCancel_Click(object sender, EventArgs e)
|
||||
{
|
||||
simCancel?.Cancel();
|
||||
}
|
||||
|
||||
public enum SweepStatus
|
||||
{
|
||||
NoSweep,
|
||||
Sweeping,
|
||||
FinishedSweep,
|
||||
CancelledSweep
|
||||
}
|
||||
}
|
||||
126
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/MainForm.resx
Normal file
126
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/MainForm.resx
Normal file
@ -0,0 +1,126 @@
|
||||
<?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>
|
||||
<metadata name="Menu.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>17, 17</value>
|
||||
</metadata>
|
||||
<metadata name="FileOpener.TrayLocation" type="System.Drawing.Point, System.Drawing, Version=4.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a">
|
||||
<value>157, 17</value>
|
||||
</metadata>
|
||||
</root>
|
||||
87
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/SweepCancelForm.Designer.cs
generated
Normal file
87
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/SweepCancelForm.Designer.cs
generated
Normal file
@ -0,0 +1,87 @@
|
||||
namespace AirTrajectoryBuilder.Forms
|
||||
{
|
||||
partial class SweepCancelForm
|
||||
{
|
||||
/// <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()
|
||||
{
|
||||
MessageLabel = new System.Windows.Forms.Label();
|
||||
YesButton = new System.Windows.Forms.Button();
|
||||
button2 = new System.Windows.Forms.Button();
|
||||
SuspendLayout();
|
||||
//
|
||||
// MessageLabel
|
||||
//
|
||||
MessageLabel.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
MessageLabel.Location = new System.Drawing.Point(12, 12);
|
||||
MessageLabel.Name = "MessageLabel";
|
||||
MessageLabel.Size = new System.Drawing.Size(637, 135);
|
||||
MessageLabel.TabIndex = 0;
|
||||
MessageLabel.Text = "Are you sure you want to cancel the sweep?";
|
||||
MessageLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// YesButton
|
||||
//
|
||||
YesButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
|
||||
YesButton.DialogResult = System.Windows.Forms.DialogResult.Yes;
|
||||
YesButton.Location = new System.Drawing.Point(178, 150);
|
||||
YesButton.Name = "YesButton";
|
||||
YesButton.Size = new System.Drawing.Size(150, 46);
|
||||
YesButton.TabIndex = 1;
|
||||
YesButton.Text = "Yes";
|
||||
YesButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// button2
|
||||
//
|
||||
button2.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Right;
|
||||
button2.DialogResult = System.Windows.Forms.DialogResult.No;
|
||||
button2.Location = new System.Drawing.Point(334, 150);
|
||||
button2.Name = "button2";
|
||||
button2.Size = new System.Drawing.Size(150, 46);
|
||||
button2.TabIndex = 2;
|
||||
button2.Text = "No";
|
||||
button2.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// SweepCancelForm
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
ClientSize = new System.Drawing.Size(661, 208);
|
||||
Controls.Add(button2);
|
||||
Controls.Add(YesButton);
|
||||
Controls.Add(MessageLabel);
|
||||
Name = "SweepCancelForm";
|
||||
Text = "Cancel the Sweep?";
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.Label MessageLabel;
|
||||
private System.Windows.Forms.Button YesButton;
|
||||
private System.Windows.Forms.Button button2;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,11 @@
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AirTrajectoryBuilder.Forms;
|
||||
|
||||
public partial class SweepCancelForm : Form
|
||||
{
|
||||
public SweepCancelForm()
|
||||
{
|
||||
InitializeComponent();
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
99
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/SweepInfoViewer.Designer.cs
generated
Normal file
99
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/SweepInfoViewer.Designer.cs
generated
Normal file
@ -0,0 +1,99 @@
|
||||
namespace AirTrajectoryBuilder.Forms
|
||||
{
|
||||
partial class SweepInfoViewer
|
||||
{
|
||||
/// <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()
|
||||
{
|
||||
SweepProgress = new System.Windows.Forms.ProgressBar();
|
||||
ProgressLabel = new System.Windows.Forms.Label();
|
||||
ResultsPanel = new System.Windows.Forms.Panel();
|
||||
ResultsLabel = new System.Windows.Forms.Label();
|
||||
ResultsPanel.SuspendLayout();
|
||||
SuspendLayout();
|
||||
//
|
||||
// SweepProgress
|
||||
//
|
||||
SweepProgress.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
SweepProgress.Location = new System.Drawing.Point(12, 229);
|
||||
SweepProgress.Name = "SweepProgress";
|
||||
SweepProgress.Size = new System.Drawing.Size(673, 20);
|
||||
SweepProgress.Style = System.Windows.Forms.ProgressBarStyle.Continuous;
|
||||
SweepProgress.TabIndex = 0;
|
||||
SweepProgress.Value = 50;
|
||||
//
|
||||
// ProgressLabel
|
||||
//
|
||||
ProgressLabel.Anchor = System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left | System.Windows.Forms.AnchorStyles.Right;
|
||||
ProgressLabel.Location = new System.Drawing.Point(12, 194);
|
||||
ProgressLabel.Name = "ProgressLabel";
|
||||
ProgressLabel.Size = new System.Drawing.Size(673, 32);
|
||||
ProgressLabel.TabIndex = 1;
|
||||
ProgressLabel.Text = "Conducting Sweep...";
|
||||
ProgressLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// ResultsPanel
|
||||
//
|
||||
ResultsPanel.AutoScroll = true;
|
||||
ResultsPanel.Controls.Add(ResultsLabel);
|
||||
ResultsPanel.Dock = System.Windows.Forms.DockStyle.Fill;
|
||||
ResultsPanel.Location = new System.Drawing.Point(0, 0);
|
||||
ResultsPanel.Name = "ResultsPanel";
|
||||
ResultsPanel.Size = new System.Drawing.Size(697, 405);
|
||||
ResultsPanel.TabIndex = 2;
|
||||
ResultsPanel.Visible = false;
|
||||
//
|
||||
// ResultsLabel
|
||||
//
|
||||
ResultsLabel.Location = new System.Drawing.Point(12, 9);
|
||||
ResultsLabel.Name = "ResultsLabel";
|
||||
ResultsLabel.Size = new System.Drawing.Size(682, 387);
|
||||
ResultsLabel.TabIndex = 0;
|
||||
ResultsLabel.Text = "label1";
|
||||
//
|
||||
// SweepInfoViewer
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
ClientSize = new System.Drawing.Size(697, 405);
|
||||
Controls.Add(ResultsPanel);
|
||||
Controls.Add(ProgressLabel);
|
||||
Controls.Add(SweepProgress);
|
||||
Name = "SweepInfoViewer";
|
||||
StartPosition = System.Windows.Forms.FormStartPosition.Manual;
|
||||
Text = "Simulation Results";
|
||||
ResultsPanel.ResumeLayout(false);
|
||||
ResumeLayout(false);
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.ProgressBar SweepProgress;
|
||||
private System.Windows.Forms.Label ProgressLabel;
|
||||
private System.Windows.Forms.Panel ResultsPanel;
|
||||
private System.Windows.Forms.Label ResultsLabel;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,97 @@
|
||||
using AirTrajectoryBuilder.ObjectModels;
|
||||
using System;
|
||||
using System.ComponentModel;
|
||||
using System.Drawing;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AirTrajectoryBuilder.Forms;
|
||||
|
||||
public partial class SweepInfoViewer : Form
|
||||
{
|
||||
private readonly MainForm mainForm;
|
||||
private SimulationResult? results;
|
||||
|
||||
public SweepInfoViewer(MainForm mainForm)
|
||||
{
|
||||
InitializeComponent();
|
||||
ResultsPanel.Visible = false;
|
||||
this.mainForm = mainForm;
|
||||
|
||||
Location =
|
||||
new Point(mainForm.Location.X + mainForm.Size.Width,
|
||||
mainForm.Location.Y + (mainForm.Size.Height - Size.Height) / 2);
|
||||
}
|
||||
|
||||
protected override void OnClosing(CancelEventArgs e)
|
||||
{
|
||||
if (!mainForm.TryCancelSweep())
|
||||
{
|
||||
e.Cancel = true;
|
||||
return;
|
||||
}
|
||||
base.OnClosing(e);
|
||||
mainForm.simViewer = null;
|
||||
}
|
||||
|
||||
public void SetMaxIters(int max)
|
||||
{
|
||||
SweepProgress.Maximum = max;
|
||||
}
|
||||
public void SetCurrentIters(int val)
|
||||
{
|
||||
SweepProgress.Value = val;
|
||||
}
|
||||
|
||||
public void CompleteSweep(SimulationResult best)
|
||||
{
|
||||
results = best;
|
||||
|
||||
SweepProgress.Visible = false;
|
||||
ProgressLabel.Visible = false;
|
||||
|
||||
DisplayResults();
|
||||
}
|
||||
public void UncompleteSweep()
|
||||
{
|
||||
SweepProgress.Visible = true;
|
||||
ProgressLabel.Visible = true;
|
||||
ResultsPanel.Visible = false;
|
||||
Invalidate(true);
|
||||
}
|
||||
|
||||
private void SetLabelSize()
|
||||
{
|
||||
ResultsLabel.Location = new Point(0, 0);
|
||||
ResultsLabel.Size = new(ResultsPanel.ClientRectangle.Width,
|
||||
ResultsLabel.PreferredHeight);
|
||||
}
|
||||
|
||||
protected override void OnResize(EventArgs e)
|
||||
{
|
||||
base.OnResize(e);
|
||||
SetLabelSize();
|
||||
}
|
||||
|
||||
private void DisplayResults()
|
||||
{
|
||||
ResultsPanel.Visible = true;
|
||||
if (results is null) return;
|
||||
|
||||
ResultsLabel.Text = $"""
|
||||
|
||||
Initial Angle: {results.StartingConditions.StartAngle:0.00} degrees
|
||||
Initial Velocity: {results.StartingConditions.StartVelocity:0.0} m/s
|
||||
Gravity: {results.StartingConditions.Gravity:0.000} m/s^2
|
||||
Delta Time: {results.StartingConditions.DeltaTime:0.000} seconds
|
||||
|
||||
Final Velocity: {results.EndSpeed:0.0} m/s
|
||||
|
||||
Duration: {results.Duration:0.00} seconds
|
||||
|
||||
Error: off by {results.EndDistanceSquared:0.000} meters
|
||||
|
||||
""";
|
||||
SetLabelSize();
|
||||
SetLabelSize(); // ...nice. But required!
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
361
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/SweepParametersForm.Designer.cs
generated
Normal file
361
AirTrajectoryBuilder/AirTrajectoryBuilder/Forms/SweepParametersForm.Designer.cs
generated
Normal file
@ -0,0 +1,361 @@
|
||||
namespace AirTrajectoryBuilder
|
||||
{
|
||||
partial class SweepParametersForm
|
||||
{
|
||||
/// <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()
|
||||
{
|
||||
AngleSweepValue = new System.Windows.Forms.TextBox();
|
||||
AngleSweepLabel = new System.Windows.Forms.Label();
|
||||
SpeedMinLabel = new System.Windows.Forms.Label();
|
||||
SpeedMinValue = new System.Windows.Forms.TextBox();
|
||||
SpeedMaxLabel = new System.Windows.Forms.Label();
|
||||
SpeedDeltaLabel = new System.Windows.Forms.Label();
|
||||
SpeedMaxValue = new System.Windows.Forms.TextBox();
|
||||
SpeedDeltaValue = new System.Windows.Forms.TextBox();
|
||||
RunButton = new System.Windows.Forms.Button();
|
||||
GravityLabel = new System.Windows.Forms.Label();
|
||||
GravityValue = new System.Windows.Forms.TextBox();
|
||||
TimeDeltaLabel = new System.Windows.Forms.Label();
|
||||
TimeDeltaValue = new System.Windows.Forms.TextBox();
|
||||
CancelButton = new System.Windows.Forms.Button();
|
||||
ProjectileMotionLabel = new System.Windows.Forms.Label();
|
||||
AirTrajectoryLabel = new System.Windows.Forms.Label();
|
||||
ObjectRadiusValue = new System.Windows.Forms.TextBox();
|
||||
ObjectRadiusLabel = new System.Windows.Forms.Label();
|
||||
MassValue = new System.Windows.Forms.TextBox();
|
||||
MassLabel = new System.Windows.Forms.Label();
|
||||
AirDensityValue = new System.Windows.Forms.TextBox();
|
||||
AirDensityLabel = new System.Windows.Forms.Label();
|
||||
DragCoefficientValue = new System.Windows.Forms.TextBox();
|
||||
DragCoefficientLabel = new System.Windows.Forms.Label();
|
||||
ResultsLabel = new System.Windows.Forms.Label();
|
||||
FileOutputLabel = new System.Windows.Forms.Label();
|
||||
FileOutputValue = new System.Windows.Forms.ComboBox();
|
||||
SuspendLayout();
|
||||
//
|
||||
// AngleSweepValue
|
||||
//
|
||||
AngleSweepValue.Location = new System.Drawing.Point(312, 122);
|
||||
AngleSweepValue.Name = "AngleSweepValue";
|
||||
AngleSweepValue.Size = new System.Drawing.Size(101, 39);
|
||||
AngleSweepValue.TabIndex = 0;
|
||||
//
|
||||
// AngleSweepLabel
|
||||
//
|
||||
AngleSweepLabel.Location = new System.Drawing.Point(82, 122);
|
||||
AngleSweepLabel.Name = "AngleSweepLabel";
|
||||
AngleSweepLabel.Size = new System.Drawing.Size(224, 39);
|
||||
AngleSweepLabel.TabIndex = 1;
|
||||
AngleSweepLabel.Text = "Angle Sweep Delta";
|
||||
AngleSweepLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// SpeedMinLabel
|
||||
//
|
||||
SpeedMinLabel.Location = new System.Drawing.Point(12, 168);
|
||||
SpeedMinLabel.Name = "SpeedMinLabel";
|
||||
SpeedMinLabel.Size = new System.Drawing.Size(159, 39);
|
||||
SpeedMinLabel.TabIndex = 2;
|
||||
SpeedMinLabel.Text = "Speed Min";
|
||||
SpeedMinLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// SpeedMinValue
|
||||
//
|
||||
SpeedMinValue.Location = new System.Drawing.Point(36, 210);
|
||||
SpeedMinValue.Name = "SpeedMinValue";
|
||||
SpeedMinValue.Size = new System.Drawing.Size(101, 39);
|
||||
SpeedMinValue.TabIndex = 3;
|
||||
//
|
||||
// SpeedMaxLabel
|
||||
//
|
||||
SpeedMaxLabel.Location = new System.Drawing.Point(177, 168);
|
||||
SpeedMaxLabel.Name = "SpeedMaxLabel";
|
||||
SpeedMaxLabel.Size = new System.Drawing.Size(159, 39);
|
||||
SpeedMaxLabel.TabIndex = 4;
|
||||
SpeedMaxLabel.Text = "Speed Max";
|
||||
SpeedMaxLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// SpeedDeltaLabel
|
||||
//
|
||||
SpeedDeltaLabel.Location = new System.Drawing.Point(342, 168);
|
||||
SpeedDeltaLabel.Name = "SpeedDeltaLabel";
|
||||
SpeedDeltaLabel.Size = new System.Drawing.Size(159, 39);
|
||||
SpeedDeltaLabel.TabIndex = 5;
|
||||
SpeedDeltaLabel.Text = "Sweep Delta";
|
||||
SpeedDeltaLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// SpeedMaxValue
|
||||
//
|
||||
SpeedMaxValue.Location = new System.Drawing.Point(204, 210);
|
||||
SpeedMaxValue.Name = "SpeedMaxValue";
|
||||
SpeedMaxValue.Size = new System.Drawing.Size(101, 39);
|
||||
SpeedMaxValue.TabIndex = 6;
|
||||
//
|
||||
// SpeedDeltaValue
|
||||
//
|
||||
SpeedDeltaValue.Location = new System.Drawing.Point(371, 210);
|
||||
SpeedDeltaValue.Name = "SpeedDeltaValue";
|
||||
SpeedDeltaValue.Size = new System.Drawing.Size(101, 39);
|
||||
SpeedDeltaValue.TabIndex = 7;
|
||||
//
|
||||
// RunButton
|
||||
//
|
||||
RunButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
|
||||
RunButton.DialogResult = System.Windows.Forms.DialogResult.OK;
|
||||
RunButton.Location = new System.Drawing.Point(198, 707);
|
||||
RunButton.Name = "RunButton";
|
||||
RunButton.Size = new System.Drawing.Size(150, 46);
|
||||
RunButton.TabIndex = 8;
|
||||
RunButton.Text = "Sweep";
|
||||
RunButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// GravityLabel
|
||||
//
|
||||
GravityLabel.Location = new System.Drawing.Point(138, 258);
|
||||
GravityLabel.Name = "GravityLabel";
|
||||
GravityLabel.Size = new System.Drawing.Size(113, 39);
|
||||
GravityLabel.TabIndex = 10;
|
||||
GravityLabel.Text = "Gravity";
|
||||
GravityLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// GravityValue
|
||||
//
|
||||
GravityValue.Location = new System.Drawing.Point(257, 258);
|
||||
GravityValue.Name = "GravityValue";
|
||||
GravityValue.Size = new System.Drawing.Size(101, 39);
|
||||
GravityValue.TabIndex = 9;
|
||||
//
|
||||
// TimeDeltaLabel
|
||||
//
|
||||
TimeDeltaLabel.Location = new System.Drawing.Point(131, 75);
|
||||
TimeDeltaLabel.Name = "TimeDeltaLabel";
|
||||
TimeDeltaLabel.Size = new System.Drawing.Size(137, 39);
|
||||
TimeDeltaLabel.TabIndex = 12;
|
||||
TimeDeltaLabel.Text = "Time Delta";
|
||||
TimeDeltaLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// TimeDeltaValue
|
||||
//
|
||||
TimeDeltaValue.Location = new System.Drawing.Point(274, 75);
|
||||
TimeDeltaValue.Name = "TimeDeltaValue";
|
||||
TimeDeltaValue.Size = new System.Drawing.Size(101, 39);
|
||||
TimeDeltaValue.TabIndex = 11;
|
||||
//
|
||||
// CancelButton
|
||||
//
|
||||
CancelButton.Anchor = System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left;
|
||||
CancelButton.DialogResult = System.Windows.Forms.DialogResult.Cancel;
|
||||
CancelButton.Location = new System.Drawing.Point(354, 707);
|
||||
CancelButton.Name = "CancelButton";
|
||||
CancelButton.Size = new System.Drawing.Size(150, 46);
|
||||
CancelButton.TabIndex = 13;
|
||||
CancelButton.Text = "Cancel";
|
||||
CancelButton.UseVisualStyleBackColor = true;
|
||||
//
|
||||
// ProjectileMotionLabel
|
||||
//
|
||||
ProjectileMotionLabel.Font = new System.Drawing.Font("Segoe UI", 10.125F, System.Drawing.FontStyle.Bold);
|
||||
ProjectileMotionLabel.Location = new System.Drawing.Point(12, 9);
|
||||
ProjectileMotionLabel.Name = "ProjectileMotionLabel";
|
||||
ProjectileMotionLabel.Size = new System.Drawing.Size(489, 39);
|
||||
ProjectileMotionLabel.TabIndex = 14;
|
||||
ProjectileMotionLabel.Text = "General Parameters:";
|
||||
ProjectileMotionLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// AirTrajectoryLabel
|
||||
//
|
||||
AirTrajectoryLabel.Font = new System.Drawing.Font("Segoe UI", 10.125F, System.Drawing.FontStyle.Bold);
|
||||
AirTrajectoryLabel.Location = new System.Drawing.Point(14, 327);
|
||||
AirTrajectoryLabel.Name = "AirTrajectoryLabel";
|
||||
AirTrajectoryLabel.Size = new System.Drawing.Size(489, 39);
|
||||
AirTrajectoryLabel.TabIndex = 15;
|
||||
AirTrajectoryLabel.Text = "Aerodynamics (Optional):";
|
||||
AirTrajectoryLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// ObjectRadiusValue
|
||||
//
|
||||
ObjectRadiusValue.Location = new System.Drawing.Point(82, 419);
|
||||
ObjectRadiusValue.Name = "ObjectRadiusValue";
|
||||
ObjectRadiusValue.Size = new System.Drawing.Size(101, 39);
|
||||
ObjectRadiusValue.TabIndex = 17;
|
||||
//
|
||||
// ObjectRadiusLabel
|
||||
//
|
||||
ObjectRadiusLabel.Location = new System.Drawing.Point(12, 377);
|
||||
ObjectRadiusLabel.Name = "ObjectRadiusLabel";
|
||||
ObjectRadiusLabel.Size = new System.Drawing.Size(239, 39);
|
||||
ObjectRadiusLabel.TabIndex = 16;
|
||||
ObjectRadiusLabel.Text = "Object Radius";
|
||||
ObjectRadiusLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// MassValue
|
||||
//
|
||||
MassValue.Location = new System.Drawing.Point(335, 419);
|
||||
MassValue.Name = "MassValue";
|
||||
MassValue.Size = new System.Drawing.Size(101, 39);
|
||||
MassValue.TabIndex = 19;
|
||||
//
|
||||
// MassLabel
|
||||
//
|
||||
MassLabel.Location = new System.Drawing.Point(265, 377);
|
||||
MassLabel.Name = "MassLabel";
|
||||
MassLabel.Size = new System.Drawing.Size(239, 39);
|
||||
MassLabel.TabIndex = 18;
|
||||
MassLabel.Text = "Object Mass";
|
||||
MassLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// AirDensityValue
|
||||
//
|
||||
AirDensityValue.Location = new System.Drawing.Point(335, 512);
|
||||
AirDensityValue.Name = "AirDensityValue";
|
||||
AirDensityValue.Size = new System.Drawing.Size(101, 39);
|
||||
AirDensityValue.TabIndex = 23;
|
||||
//
|
||||
// AirDensityLabel
|
||||
//
|
||||
AirDensityLabel.Location = new System.Drawing.Point(265, 470);
|
||||
AirDensityLabel.Name = "AirDensityLabel";
|
||||
AirDensityLabel.Size = new System.Drawing.Size(239, 39);
|
||||
AirDensityLabel.TabIndex = 22;
|
||||
AirDensityLabel.Text = "Air Density";
|
||||
AirDensityLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// DragCoefficientValue
|
||||
//
|
||||
DragCoefficientValue.Location = new System.Drawing.Point(82, 512);
|
||||
DragCoefficientValue.Name = "DragCoefficientValue";
|
||||
DragCoefficientValue.Size = new System.Drawing.Size(101, 39);
|
||||
DragCoefficientValue.TabIndex = 21;
|
||||
//
|
||||
// DragCoefficientLabel
|
||||
//
|
||||
DragCoefficientLabel.Location = new System.Drawing.Point(12, 470);
|
||||
DragCoefficientLabel.Name = "DragCoefficientLabel";
|
||||
DragCoefficientLabel.Size = new System.Drawing.Size(239, 39);
|
||||
DragCoefficientLabel.TabIndex = 20;
|
||||
DragCoefficientLabel.Text = "Drag Coefficient";
|
||||
DragCoefficientLabel.TextAlign = System.Drawing.ContentAlignment.MiddleCenter;
|
||||
//
|
||||
// ResultsLabel
|
||||
//
|
||||
ResultsLabel.Font = new System.Drawing.Font("Segoe UI", 10.125F, System.Drawing.FontStyle.Bold);
|
||||
ResultsLabel.Location = new System.Drawing.Point(14, 583);
|
||||
ResultsLabel.Name = "ResultsLabel";
|
||||
ResultsLabel.Size = new System.Drawing.Size(489, 39);
|
||||
ResultsLabel.TabIndex = 24;
|
||||
ResultsLabel.Text = "Results:";
|
||||
ResultsLabel.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
|
||||
//
|
||||
// FileOutputLabel
|
||||
//
|
||||
FileOutputLabel.Location = new System.Drawing.Point(37, 622);
|
||||
FileOutputLabel.Name = "FileOutputLabel";
|
||||
FileOutputLabel.Size = new System.Drawing.Size(156, 64);
|
||||
FileOutputLabel.TabIndex = 25;
|
||||
FileOutputLabel.Text = "File Output";
|
||||
FileOutputLabel.TextAlign = System.Drawing.ContentAlignment.MiddleRight;
|
||||
//
|
||||
// FileOutputValue
|
||||
//
|
||||
FileOutputValue.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
|
||||
FileOutputValue.FormattingEnabled = true;
|
||||
FileOutputValue.Items.AddRange(new object[] { "None", "Text - Best", "Text - All", "Json - Best", "Json - All", "Binary - Best", "Binary - All" });
|
||||
FileOutputValue.Location = new System.Drawing.Point(199, 635);
|
||||
FileOutputValue.MaxLength = 1;
|
||||
FileOutputValue.Name = "FileOutputValue";
|
||||
FileOutputValue.Size = new System.Drawing.Size(242, 40);
|
||||
FileOutputValue.TabIndex = 26;
|
||||
//
|
||||
// SweepParametersForm
|
||||
//
|
||||
AutoScaleDimensions = new System.Drawing.SizeF(13F, 32F);
|
||||
AutoScaleMode = System.Windows.Forms.AutoScaleMode.Font;
|
||||
ClientSize = new System.Drawing.Size(516, 765);
|
||||
Controls.Add(FileOutputValue);
|
||||
Controls.Add(FileOutputLabel);
|
||||
Controls.Add(ResultsLabel);
|
||||
Controls.Add(AirDensityValue);
|
||||
Controls.Add(AirDensityLabel);
|
||||
Controls.Add(DragCoefficientValue);
|
||||
Controls.Add(DragCoefficientLabel);
|
||||
Controls.Add(MassValue);
|
||||
Controls.Add(MassLabel);
|
||||
Controls.Add(ObjectRadiusValue);
|
||||
Controls.Add(ObjectRadiusLabel);
|
||||
Controls.Add(AirTrajectoryLabel);
|
||||
Controls.Add(ProjectileMotionLabel);
|
||||
Controls.Add(CancelButton);
|
||||
Controls.Add(TimeDeltaLabel);
|
||||
Controls.Add(TimeDeltaValue);
|
||||
Controls.Add(GravityLabel);
|
||||
Controls.Add(GravityValue);
|
||||
Controls.Add(RunButton);
|
||||
Controls.Add(SpeedDeltaValue);
|
||||
Controls.Add(SpeedMaxValue);
|
||||
Controls.Add(SpeedDeltaLabel);
|
||||
Controls.Add(SpeedMaxLabel);
|
||||
Controls.Add(SpeedMinValue);
|
||||
Controls.Add(SpeedMinLabel);
|
||||
Controls.Add(AngleSweepLabel);
|
||||
Controls.Add(AngleSweepValue);
|
||||
FormBorderStyle = System.Windows.Forms.FormBorderStyle.FixedSingle;
|
||||
Name = "SweepParametersForm";
|
||||
Text = "Set Sweep Parameters";
|
||||
ResumeLayout(false);
|
||||
PerformLayout();
|
||||
}
|
||||
|
||||
#endregion
|
||||
|
||||
private System.Windows.Forms.TextBox AngleSweepValue;
|
||||
private System.Windows.Forms.Label AngleSweepLabel;
|
||||
private System.Windows.Forms.Label SpeedMinLabel;
|
||||
private System.Windows.Forms.TextBox SpeedMinValue;
|
||||
private System.Windows.Forms.Label SpeedMaxLabel;
|
||||
private System.Windows.Forms.Label SpeedDeltaLabel;
|
||||
private System.Windows.Forms.TextBox SpeedMaxValue;
|
||||
private System.Windows.Forms.TextBox SpeedDeltaValue;
|
||||
private System.Windows.Forms.Button RunButton;
|
||||
private System.Windows.Forms.Label GravityLabel;
|
||||
private System.Windows.Forms.TextBox GravityValue;
|
||||
private System.Windows.Forms.Label TimeDeltaLabel;
|
||||
private System.Windows.Forms.TextBox TimeDeltaValue;
|
||||
private System.Windows.Forms.Button CancelButton;
|
||||
private System.Windows.Forms.Label ProjectileMotionLabel;
|
||||
private System.Windows.Forms.Label AirTrajectoryLabel;
|
||||
private System.Windows.Forms.TextBox ObjectRadiusValue;
|
||||
private System.Windows.Forms.Label ObjectRadiusLabel;
|
||||
private System.Windows.Forms.TextBox MassValue;
|
||||
private System.Windows.Forms.Label MassLabel;
|
||||
private System.Windows.Forms.TextBox AirDensityValue;
|
||||
private System.Windows.Forms.Label AirDensityLabel;
|
||||
private System.Windows.Forms.TextBox DragCoefficientValue;
|
||||
private System.Windows.Forms.Label DragCoefficientLabel;
|
||||
private System.Windows.Forms.Label ResultsLabel;
|
||||
private System.Windows.Forms.Label FileOutputLabel;
|
||||
private System.Windows.Forms.ComboBox FileOutputValue;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,156 @@
|
||||
using AirTrajectoryBuilder.ObjectModels;
|
||||
using System.Windows.Forms;
|
||||
using System.ComponentModel;
|
||||
using System.IO;
|
||||
using System;
|
||||
|
||||
namespace AirTrajectoryBuilder;
|
||||
|
||||
public partial class SweepParametersForm : Form
|
||||
{
|
||||
private static readonly FileMode[] fileModeValues = Enum.GetValues<FileMode>();
|
||||
|
||||
public double AngleDelta = 0.1,
|
||||
SpeedDelta = 0.5,
|
||||
SpeedMin = 10,
|
||||
SpeedMax = 100,
|
||||
Gravity = -9.81,
|
||||
TimeDelta = 0.01;
|
||||
|
||||
public double ObjectRadius = 0,
|
||||
DragCoefficient = 0,
|
||||
Mass = 0,
|
||||
AirDensity = 1.225;
|
||||
|
||||
public ResultsFileMode FileMode = ResultsFileMode.None;
|
||||
|
||||
private static SweepParameters? previous = null;
|
||||
|
||||
[DesignerSerializationVisibility(DesignerSerializationVisibility.Hidden)]
|
||||
public SweepParameters Result
|
||||
{
|
||||
get
|
||||
{
|
||||
SweepParameters result = new()
|
||||
{
|
||||
AngleDelta = AngleDelta,
|
||||
SpeedDelta = SpeedDelta,
|
||||
SpeedMin = SpeedMin,
|
||||
SpeedMax = SpeedMax,
|
||||
Gravity = Gravity,
|
||||
TimeDelta = TimeDelta,
|
||||
ObjectRadius = ObjectRadius,
|
||||
DragCoefficient = DragCoefficient,
|
||||
Mass = Mass,
|
||||
AirDensity = AirDensity,
|
||||
Tolerance = 1e-1, // TODO
|
||||
Scene = form.Scene,
|
||||
FileMode = FileMode
|
||||
};
|
||||
previous = result;
|
||||
return result;
|
||||
}
|
||||
set
|
||||
{
|
||||
AngleDelta = value.AngleDelta;
|
||||
SpeedDelta = value.SpeedDelta;
|
||||
SpeedMin = value.SpeedMin;
|
||||
SpeedMax = value.SpeedMax;
|
||||
Gravity = value.Gravity;
|
||||
TimeDelta = value.TimeDelta;
|
||||
ObjectRadius = value.ObjectRadius;
|
||||
DragCoefficient = value.DragCoefficient;
|
||||
Mass = value.Mass;
|
||||
AirDensity = value.AirDensity;
|
||||
FileMode = value.FileMode;
|
||||
|
||||
previous = value;
|
||||
SetValues();
|
||||
}
|
||||
}
|
||||
private readonly MainForm form;
|
||||
|
||||
public SweepParametersForm(MainForm form)
|
||||
{
|
||||
InitializeComponent();
|
||||
this.form = form;
|
||||
|
||||
AngleSweepValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(AngleSweepValue.Text, out AngleDelta))
|
||||
AngleSweepValue.Text = AngleDelta.ToString();
|
||||
};
|
||||
SpeedDeltaValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(SpeedDeltaValue.Text, out SpeedDelta))
|
||||
SpeedDeltaValue.Text = SpeedDelta.ToString();
|
||||
};
|
||||
SpeedMinValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(SpeedMinValue.Text, out SpeedMin))
|
||||
SpeedMinValue.Text = SpeedMin.ToString();
|
||||
};
|
||||
SpeedMaxValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(SpeedMaxValue.Text, out SpeedMax))
|
||||
SpeedMaxValue.Text = SpeedMax.ToString();
|
||||
};
|
||||
GravityValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(GravityValue.Text, out Gravity))
|
||||
GravityValue.Text = Gravity.ToString();
|
||||
};
|
||||
TimeDeltaValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(TimeDeltaValue.Text, out TimeDelta))
|
||||
TimeDeltaValue.Text = TimeDelta.ToString();
|
||||
};
|
||||
ObjectRadiusValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(ObjectRadiusValue.Text, out ObjectRadius))
|
||||
ObjectRadiusValue.Text = ObjectRadius.ToString();
|
||||
};
|
||||
MassValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(MassValue.Text, out Mass))
|
||||
MassValue.Text = Mass.ToString();
|
||||
};
|
||||
DragCoefficientValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(DragCoefficientValue.Text, out DragCoefficient))
|
||||
DragCoefficientValue.Text = DragCoefficient.ToString();
|
||||
};
|
||||
AirDensityValue.Leave += (o, e) =>
|
||||
{
|
||||
if (!double.TryParse(AirDensityValue.Text, out AirDensity))
|
||||
AirDensityValue.Text = AirDensity.ToString();
|
||||
};
|
||||
FileOutputValue.Leave += (o, e) =>
|
||||
{
|
||||
int index = FileOutputValue.SelectedIndex;
|
||||
if (index < 0 || index >= FileOutputValue.Items.Count)
|
||||
{
|
||||
FileOutputValue.SelectedIndex = (int)FileMode;
|
||||
}
|
||||
else FileMode = (ResultsFileMode)FileOutputValue.SelectedIndex;
|
||||
};
|
||||
|
||||
if (previous is null) SetValues();
|
||||
else Result = previous;
|
||||
}
|
||||
|
||||
private void SetValues()
|
||||
{
|
||||
AngleSweepValue.Text = AngleDelta.ToString();
|
||||
SpeedDeltaValue.Text = SpeedDelta.ToString();
|
||||
SpeedMinValue.Text = SpeedMin.ToString();
|
||||
SpeedMaxValue.Text = SpeedMax.ToString();
|
||||
GravityValue.Text = Gravity.ToString();
|
||||
TimeDeltaValue.Text = TimeDelta.ToString();
|
||||
ObjectRadiusValue.Text = ObjectRadius.ToString();
|
||||
MassValue.Text = Mass.ToString();
|
||||
DragCoefficientValue.Text = DragCoefficient.ToString();
|
||||
AirDensityValue.Text = AirDensity.ToString();
|
||||
FileOutputValue.SelectedIndex = (int)FileMode;
|
||||
}
|
||||
}
|
||||
@ -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>
|
||||
@ -0,0 +1,9 @@
|
||||
using Nerd_STF.Mathematics;
|
||||
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public interface ISceneObject
|
||||
{
|
||||
public bool Contains(Float2 point);
|
||||
public ISceneObject DeepCopy();
|
||||
}
|
||||
@ -0,0 +1,12 @@
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public enum ResultsFileMode
|
||||
{
|
||||
None,
|
||||
TextBest,
|
||||
TextAll,
|
||||
JsonBest,
|
||||
JsonAll,
|
||||
BinaryBest,
|
||||
BinaryAll
|
||||
}
|
||||
146
AirTrajectoryBuilder/AirTrajectoryBuilder/ObjectModels/Scene.cs
Normal file
146
AirTrajectoryBuilder/AirTrajectoryBuilder/ObjectModels/Scene.cs
Normal file
@ -0,0 +1,146 @@
|
||||
using Nerd_STF.Mathematics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AirTrajectoryBuilder.ObjectModels
|
||||
{
|
||||
public class Scene
|
||||
{
|
||||
public static Scene Default => new()
|
||||
{
|
||||
Width = 100,
|
||||
Height = 60,
|
||||
Objects = [],
|
||||
HasBeenSaved = true,
|
||||
FilePath = null,
|
||||
EndAt = (100, 0)
|
||||
};
|
||||
|
||||
public double Width { get; set; }
|
||||
public double Height { get; set; }
|
||||
|
||||
public Float2 StartAt { get; set; }
|
||||
public Float2 EndAt { get; set; }
|
||||
|
||||
public bool HasBeenSaved { get; set; }
|
||||
public string? FilePath { get; set; }
|
||||
|
||||
public List<ISceneObject> Objects { get; private set; } = [];
|
||||
|
||||
public Scene DeepCopy()
|
||||
{
|
||||
Scene copy = new()
|
||||
{
|
||||
Width = Width,
|
||||
Height = Height,
|
||||
StartAt = StartAt,
|
||||
EndAt = EndAt,
|
||||
HasBeenSaved = HasBeenSaved,
|
||||
FilePath = FilePath,
|
||||
Objects = []
|
||||
};
|
||||
foreach (ISceneObject obj in Objects) copy.Objects.Add(obj.DeepCopy());
|
||||
return copy;
|
||||
}
|
||||
|
||||
public static Scene Read(string path)
|
||||
{
|
||||
if (!File.Exists(path)) throw new IOException();
|
||||
StreamReader reader = new(path);
|
||||
|
||||
string? line;
|
||||
Scene? scene = null;
|
||||
while ((line = reader.ReadLine()) is not null)
|
||||
{
|
||||
if (string.IsNullOrWhiteSpace(line)) continue;
|
||||
string[] parts = line.Split(' ');
|
||||
|
||||
switch (parts[0])
|
||||
{
|
||||
case "Scene":
|
||||
if (parts.Length != 4) throw new IOException();
|
||||
else if (parts[2] != "by") throw new IOException();
|
||||
scene = new()
|
||||
{
|
||||
Width = double.Parse(parts[1]),
|
||||
Height = double.Parse(parts[3]),
|
||||
Objects = [],
|
||||
HasBeenSaved = true,
|
||||
FilePath = path,
|
||||
};
|
||||
break;
|
||||
case "Rect":
|
||||
if (scene is null) throw new IOException();
|
||||
else if (parts.Length != 6) throw new IOException();
|
||||
else if (parts[3] != "to") throw new IOException();
|
||||
SceneRect rect = new()
|
||||
{
|
||||
From = (double.Parse(parts[1]), double.Parse(parts[2])),
|
||||
To = (double.Parse(parts[4]), double.Parse(parts[5]))
|
||||
};
|
||||
scene.Objects.Add(rect);
|
||||
break;
|
||||
case "Tri":
|
||||
if (scene is null) throw new IOException();
|
||||
else if (parts.Length != 9) throw new IOException();
|
||||
else if (parts[3] != "and" || parts[6] != "and") throw new IOException();
|
||||
SceneTri tri = new()
|
||||
{
|
||||
A = (double.Parse(parts[1]), double.Parse(parts[2])),
|
||||
B = (double.Parse(parts[4]), double.Parse(parts[5])),
|
||||
C = (double.Parse(parts[7]), double.Parse(parts[8]))
|
||||
};
|
||||
scene.Objects.Add(tri);
|
||||
break;
|
||||
case "Ellipse":
|
||||
if (scene is null) throw new IOException();
|
||||
else if (parts.Length != 7) throw new IOException();
|
||||
else if (parts[3] != "and" || parts[5] != "by") throw new IOException();
|
||||
SceneEllipse ellipse = new()
|
||||
{
|
||||
Position = (double.Parse(parts[1]), double.Parse(parts[2])),
|
||||
Size = (double.Parse(parts[4]), double.Parse(parts[6]))
|
||||
};
|
||||
scene.Objects.Add(ellipse);
|
||||
break;
|
||||
case "Start":
|
||||
if (scene is null) throw new IOException();
|
||||
else if (parts.Length != 3) throw new IOException();
|
||||
scene.StartAt = (double.Parse(parts[1]), double.Parse(parts[2]));
|
||||
break;
|
||||
case "End":
|
||||
if (scene is null) throw new IOException();
|
||||
else if (parts.Length != 3) throw new IOException();
|
||||
scene.EndAt = (double.Parse(parts[1]), double.Parse(parts[2]));
|
||||
break;
|
||||
default: throw new IOException();
|
||||
}
|
||||
}
|
||||
reader.Close();
|
||||
return scene ?? Default;
|
||||
}
|
||||
public void Write()
|
||||
{
|
||||
StreamWriter writer = new(FilePath ?? throw new IOException());
|
||||
|
||||
writer.WriteLine($"Scene {Width} by {Height}\n");
|
||||
foreach (ISceneObject obj in Objects)
|
||||
{
|
||||
if (obj is SceneRect objRect)
|
||||
{
|
||||
writer.WriteLine($"Rect {objRect.From.x} {objRect.From.y} to {objRect.To.x} {objRect.To.y}");
|
||||
}
|
||||
else if (obj is SceneTri objTri)
|
||||
{
|
||||
writer.WriteLine($"Tri {objTri.A.x} {objTri.A.y} and {objTri.B.x} {objTri.B.y} and {objTri.C.x} {objTri.C.y}");
|
||||
}
|
||||
else if (obj is SceneEllipse objEllipse)
|
||||
{
|
||||
writer.WriteLine($"Ellipse {objEllipse.Position.x} {objEllipse.Position.y} and {objEllipse.Size.x} by {objEllipse.Size.y}");
|
||||
}
|
||||
}
|
||||
|
||||
writer.Close();
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
using Nerd_STF.Mathematics;
|
||||
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public class SceneEllipse : ISceneObject
|
||||
{
|
||||
public Float2 Position { get; set; }
|
||||
public Float2 Size { get; set; }
|
||||
|
||||
public bool Contains(Float2 point)
|
||||
{
|
||||
Float2 p = point - Position;
|
||||
Float2 delta = p * 2 / Size;
|
||||
|
||||
delta.x *= delta.x;
|
||||
delta.y *= delta.y;
|
||||
return delta.x + delta.y <= 1;
|
||||
}
|
||||
public ISceneObject DeepCopy() => new SceneEllipse()
|
||||
{
|
||||
Position = Position,
|
||||
Size = Size
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
using Nerd_STF.Mathematics;
|
||||
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public class SceneRect : ISceneObject
|
||||
{
|
||||
public Float2 From { get; set; }
|
||||
public Float2 To { get; set; }
|
||||
|
||||
public bool Contains(Float2 p)
|
||||
{
|
||||
double minX = double.Min(From.x, To.x), maxX = double.Max(From.x, To.x),
|
||||
minY = double.Min(From.y, To.y), maxY = double.Max(From.y, To.y);
|
||||
|
||||
return p.x >= minX && p.x <= maxX &&
|
||||
p.y >= minY && p.y <= maxY;
|
||||
}
|
||||
|
||||
public ISceneObject DeepCopy() => new SceneRect()
|
||||
{
|
||||
From = From,
|
||||
To = To
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,33 @@
|
||||
using Nerd_STF.Mathematics;
|
||||
using System;
|
||||
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public class SceneTri : ISceneObject
|
||||
{
|
||||
public Float2 A { get; set; }
|
||||
public Float2 B { get; set; }
|
||||
public Float2 C { get; set; }
|
||||
|
||||
private static double Area(Float2 a, Float2 b, Float2 c)
|
||||
{
|
||||
return Math.Abs((a.x * (b.y - c.y) +
|
||||
b.x * (c.y - a.y) +
|
||||
c.x * (a.y - b.y)) * 0.5);
|
||||
}
|
||||
public bool Contains(Float2 p)
|
||||
{
|
||||
double area = Area(A, B, C),
|
||||
a1 = Area(p, B, C),
|
||||
a2 = Area(A, p, C),
|
||||
a3 = Area(A, B, p);
|
||||
return area == a1 + a2 + a3;
|
||||
}
|
||||
|
||||
public ISceneObject DeepCopy() => new SceneTri()
|
||||
{
|
||||
A = A,
|
||||
B = B,
|
||||
C = C
|
||||
};
|
||||
}
|
||||
@ -0,0 +1,16 @@
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public class SimulationParameters
|
||||
{
|
||||
public required double StartAngle;
|
||||
public required double StartVelocity;
|
||||
public required double DeltaTime;
|
||||
public required double Gravity;
|
||||
public required double ToleranceSquared;
|
||||
public required double ObjectRadius;
|
||||
public required double DragCoefficient;
|
||||
public required double Mass;
|
||||
public required double AirDensity;
|
||||
public required Scene Scene;
|
||||
public required bool GenerateTable;
|
||||
}
|
||||
@ -0,0 +1,24 @@
|
||||
using Nerd_STF.Mathematics;
|
||||
using System.Collections.Generic;
|
||||
using System.IO;
|
||||
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public class SimulationResult
|
||||
{
|
||||
public double Duration;
|
||||
|
||||
public double EndDistanceSquared;
|
||||
|
||||
public double EndSpeed;
|
||||
|
||||
public List<Float2> Trail = [];
|
||||
public List<TableEntry>? Table = null;
|
||||
|
||||
public SimulationParameters StartingConditions;
|
||||
|
||||
public SimulationResult(SimulationParameters starting)
|
||||
{
|
||||
StartingConditions = starting;
|
||||
}
|
||||
}
|
||||
@ -0,0 +1,18 @@
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public class SweepParameters
|
||||
{
|
||||
public required double AngleDelta, TimeDelta;
|
||||
public required double SpeedMin, SpeedMax, SpeedDelta;
|
||||
public required double Gravity;
|
||||
public required double Tolerance;
|
||||
|
||||
public required double ObjectRadius;
|
||||
public required double DragCoefficient;
|
||||
public required double Mass;
|
||||
public required double AirDensity;
|
||||
|
||||
public required ResultsFileMode FileMode;
|
||||
|
||||
public required Scene Scene;
|
||||
}
|
||||
@ -0,0 +1,5 @@
|
||||
using Nerd_STF.Mathematics;
|
||||
|
||||
namespace AirTrajectoryBuilder.ObjectModels;
|
||||
|
||||
public record class TableEntry(Float2 Position, Float2 Velocity, Float2 Acceleration);
|
||||
41
AirTrajectoryBuilder/AirTrajectoryBuilder/Program.cs
Normal file
41
AirTrajectoryBuilder/AirTrajectoryBuilder/Program.cs
Normal file
@ -0,0 +1,41 @@
|
||||
/**********722871**********
|
||||
* Date: 12/2/2024
|
||||
* Programmer: Kyle Gilbert
|
||||
* Program Name: AirTrajectoryBuilder
|
||||
* Program Description: Sweeps possible launch angles and speeds in a given scene
|
||||
* and applies aerodynamic physics.
|
||||
**************************/
|
||||
|
||||
using AirTrajectoryBuilder.ObjectModels;
|
||||
using System;
|
||||
using System.Windows.Forms;
|
||||
|
||||
namespace AirTrajectoryBuilder;
|
||||
|
||||
public static class Program
|
||||
{
|
||||
[STAThread]
|
||||
public static void Main(string[] args)
|
||||
{
|
||||
Application.EnableVisualStyles();
|
||||
Application.SetCompatibleTextRenderingDefault(false);
|
||||
Application.SetHighDpiMode(HighDpiMode.SystemAware);
|
||||
|
||||
Scene? scene;
|
||||
if (args.Length > 0)
|
||||
{
|
||||
try
|
||||
{
|
||||
scene = Scene.Read(args[0]);
|
||||
}
|
||||
catch (Exception ex)
|
||||
{
|
||||
MessageBox.Show($"Error opening scene file: {ex.GetType().Name}");
|
||||
scene = null;
|
||||
}
|
||||
}
|
||||
else scene = null;
|
||||
|
||||
Application.Run(new MainForm(scene));
|
||||
}
|
||||
}
|
||||
@ -27,7 +27,12 @@ I have about 1-2 weeks for each project. Check the Git commits for specific date
|
||||
- Data transfer is automatically encrypted behind the scenes (though the server decrypts it when it gets it).
|
||||
- Allows for as many people to connect as need be.
|
||||
- The client is somewhat janky, but the server has zero issues from my testing.
|
||||
- TypingTest
|
||||
- TypingTest/
|
||||
- A small game I made in like 2 hours. Using a list of words, it picks one at random and the user has to type it out.
|
||||
- It has a one-minute timer, and highlights the letters you got right.
|
||||
- Shows results as characters per minute, words per minute, and accuracy percentage at the end.
|
||||
- AirTrajectoryBuilder
|
||||
- A program I wrote that simulates the air trajectory of a projectile. Finished a while ago.
|
||||
- Create a `.sce` file (a somewhat easy to use plain text format)
|
||||
- Nice colors for each object. Scales seamlessly with a higher DPI.
|
||||
- Sweeps possible angles and speeds to try and find the path that brings the ball closest to the end point.
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user