StarSim

StarSim.git
git clone git://git.lenczewski.org/StarSim.git
Log | Files | Refs | README | LICENSE

commit 1a4451c46a11344ba76c2b8c98ed34c27022cc79
parent 7ec58227400e51bb5eed6b9022918c1d317ed4e5
Author: Mikolaj Lenczewski <33129490+EnderRifter@users.noreply.github.com>
Date:   Tue,  2 Jul 2019 16:13:21 +0100

Refactored orbit tracers into separate class.

Diffstat:
MStarSim/StarSim.sln | 28++++++++++++++++++++++++++++
MStarSim/StarSim/Program.cs | 1+
MStarSim/StarSim/StarSim.csproj | 1+
MStarSim/StarSimGui/StarSimGui.csproj | 40++++++++++++++++++++++++++++++++++++++++
MStarSim/StarSimLib/Constants.cs | 5+++--
AStarSim/StarSimLib/Data Structures/Body.cs | 238+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
AStarSim/StarSimLib/Data Structures/EulerAngle.cs | 37+++++++++++++++++++++++++++++++++++++
DStarSim/StarSimLib/Data Structures/EulerAngles.cs | 37-------------------------------------
AStarSim/StarSimLib/Data Structures/OrbitTracer.cs | 94+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
MStarSim/StarSimLib/Graphics/Drawer.cs | 6+++---
DStarSim/StarSimLib/Physics/Body.cs | 282-------------------------------------------------------------------------------
MStarSim/StarSimLib/StarSimLib.csproj | 17+++++++++++++++++
MStarSim/StarSimLib/StarSimLib.xml | 104++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
MStarSim/StarSimLib/UI/InputHandler.cs | 13+++++++++++--
14 files changed, 539 insertions(+), 364 deletions(-)

diff --git a/StarSim/StarSim.sln b/StarSim/StarSim.sln @@ -12,21 +12,49 @@ EndProject Global GlobalSection(SolutionConfigurationPlatforms) = preSolution Debug|Any CPU = Debug|Any CPU + Debug|x64 = Debug|x64 + Debug|x86 = Debug|x86 Release|Any CPU = Release|Any CPU + Release|x64 = Release|x64 + Release|x86 = Release|x86 EndGlobalSection GlobalSection(ProjectConfigurationPlatforms) = postSolution {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Debug|Any CPU.Build.0 = Debug|Any CPU + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Debug|x64.ActiveCfg = Debug|x64 + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Debug|x64.Build.0 = Debug|x64 + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Debug|x86.ActiveCfg = Debug|x86 + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Debug|x86.Build.0 = Debug|x86 {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Release|Any CPU.ActiveCfg = Release|Any CPU {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Release|Any CPU.Build.0 = Release|Any CPU + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Release|x64.ActiveCfg = Release|x64 + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Release|x64.Build.0 = Release|x64 + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Release|x86.ActiveCfg = Release|x86 + {0FA6CC2D-C2B7-461B-AADC-4E3AECD2C05C}.Release|x86.Build.0 = Release|x86 {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Debug|Any CPU.Build.0 = Debug|Any CPU + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Debug|x64.ActiveCfg = Debug|x64 + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Debug|x64.Build.0 = Debug|x64 + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Debug|x86.ActiveCfg = Debug|x86 + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Debug|x86.Build.0 = Debug|x86 {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Release|Any CPU.ActiveCfg = Release|Any CPU {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Release|Any CPU.Build.0 = Release|Any CPU + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Release|x64.ActiveCfg = Release|x64 + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Release|x64.Build.0 = Release|x64 + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Release|x86.ActiveCfg = Release|x86 + {E7DA74EF-E69A-4165-BF3D-5B641D991D75}.Release|x86.Build.0 = Release|x86 {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Debug|Any CPU.ActiveCfg = Debug|Any CPU {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Debug|Any CPU.Build.0 = Debug|Any CPU + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Debug|x64.ActiveCfg = Debug|x64 + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Debug|x64.Build.0 = Debug|x64 + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Debug|x86.ActiveCfg = Debug|x86 + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Debug|x86.Build.0 = Debug|x86 {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Release|Any CPU.ActiveCfg = Release|Any CPU {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Release|Any CPU.Build.0 = Release|Any CPU + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Release|x64.ActiveCfg = Release|x64 + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Release|x64.Build.0 = Release|x64 + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Release|x86.ActiveCfg = Release|x86 + {83F04A74-D9DB-4C8C-ABDC-3610099BCC51}.Release|x86.Build.0 = Release|x86 EndGlobalSection GlobalSection(SolutionProperties) = preSolution HideSolutionNode = FALSE diff --git a/StarSim/StarSim/Program.cs b/StarSim/StarSim/Program.cs @@ -4,6 +4,7 @@ using SFML.Graphics; using SFML.System; using SFML.Window; using StarSimLib; +using StarSimLib.Data_Structures; using StarSimLib.Graphics; using StarSimLib.Physics; using StarSimLib.UI; diff --git a/StarSim/StarSim/StarSim.csproj b/StarSim/StarSim/StarSim.csproj @@ -3,6 +3,7 @@ <PropertyGroup> <OutputType>Exe</OutputType> <TargetFramework>netcoreapp2.2</TargetFramework> + <Platforms>AnyCPU;x64;x86</Platforms> </PropertyGroup> <ItemGroup> diff --git a/StarSim/StarSimGui/StarSimGui.csproj b/StarSim/StarSimGui/StarSimGui.csproj @@ -37,6 +37,46 @@ <ErrorReport>prompt</ErrorReport> <WarningLevel>4</WarningLevel> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x64'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\x64\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>x64</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + <Prefer32Bit>true</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x64'"> + <OutputPath>bin\x64\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <Optimize>true</Optimize> + <DebugType>pdbonly</DebugType> + <PlatformTarget>x64</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + <Prefer32Bit>true</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Debug|x86'"> + <DebugSymbols>true</DebugSymbols> + <OutputPath>bin\x86\Debug\</OutputPath> + <DefineConstants>DEBUG;TRACE</DefineConstants> + <DebugType>full</DebugType> + <PlatformTarget>x86</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + <Prefer32Bit>true</Prefer32Bit> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)' == 'Release|x86'"> + <OutputPath>bin\x86\Release\</OutputPath> + <DefineConstants>TRACE</DefineConstants> + <Optimize>true</Optimize> + <DebugType>pdbonly</DebugType> + <PlatformTarget>x86</PlatformTarget> + <ErrorReport>prompt</ErrorReport> + <CodeAnalysisRuleSet>MinimumRecommendedRules.ruleset</CodeAnalysisRuleSet> + <Prefer32Bit>true</Prefer32Bit> + </PropertyGroup> <ItemGroup> <Reference Include="Castle.Core, Version=4.0.0.0, Culture=neutral, PublicKeyToken=407dd0808d44fbdc, processorArchitecture=MSIL"> <HintPath>..\packages\Castle.Core.4.4.0\lib\net45\Castle.Core.dll</HintPath> diff --git a/StarSim/StarSimLib/Constants.cs b/StarSim/StarSimLib/Constants.cs @@ -1,4 +1,5 @@ -using StarSimLib.Physics; +using StarSimLib.Data_Structures; +using StarSimLib.Physics; namespace StarSimLib { @@ -20,7 +21,7 @@ namespace StarSimLib /// <summary> /// The amount of degrees by which the view will be rotated in any given direction. /// </summary> - public const double EulerRotationStep = 1; + public const double EulerRotationStep = 0.5; /// <summary> /// The frame rate limit for the program. diff --git a/StarSim/StarSimLib/Data Structures/Body.cs b/StarSim/StarSimLib/Data Structures/Body.cs @@ -0,0 +1,237 @@ +using System; + +namespace StarSimLib.Data_Structures +{ + /// <summary> + /// Represents a stellar body. + /// </summary> + public class Body + { + /// <summary> + /// Describes how the <see cref="Body"/> instance should be formatted as a <see cref="string"/>. + /// </summary> + private const string BodyFormatString = + "Body {0,2}.{1,-4}: Pos-{2}, Vel-{3} Mass-{4,3}"; + + /// <summary> + /// The orbit tracers for this instance. + /// </summary> + private readonly OrbitTracer orbitTracer; + + /// <summary> + /// The backing field for the <see cref="Force"/> property. + /// </summary> + private Vector4d force; + + /// <summary> + /// Backing field for the <see cref="Mass"/> property. + /// </summary> + private double mass; + + /// <summary> + /// Backing field for the <see cref="Position"/> property. + /// </summary> + private Vector4d position; + + /// <summary> + /// Backing field for the <see cref="Velocity"/> property. + /// </summary> + private Vector4d velocity; + + /// <summary> + /// The generation that this body belongs to. + /// </summary> + public readonly uint Generation; + + /// <summary> + /// The unique id for this body. + /// </summary> + public readonly uint Id; + + /// <summary> + /// Initialises a new instance of the <see cref="Body"/> class. + /// </summary> + /// <param name="position">The starting position of the <see cref="Body"/>.</param> + /// <param name="velocity">The starting velocity of the <see cref="Body"/>.</param> + /// <param name="mass">The starting mass of the <see cref="Body"/>.</param> + /// <param name="generation">The generation that this <see cref="Body"/> belongs to.</param> + /// <param name="id">The unique id for this body.</param> + public Body(Vector4d position, Vector4d velocity, double mass, uint generation = 1, uint id = 1) + { + Generation = generation; + Id = id; + + this.position = position; + this.position.W = 1; + this.velocity = velocity; + this.mass = mass; + + force = new Vector4d(); + orbitTracer = new OrbitTracer(); + } + + /// <summary> + /// The current force on the <see cref="Body"/> in 3D space. + /// </summary> + public Vector4d Force + { + get { return force; } + } + + /// <summary> + /// The mass of the <see cref="Body"/>. + /// </summary> + public double Mass + { + get { return mass; } + } + + /// <summary> + /// The <see cref="Data_Structures.OrbitTracer"/> for this instance. + /// </summary> + public ref readonly OrbitTracer OrbitTracer + { + get { return ref orbitTracer; } + } + + /// <summary> + /// The current position of the <see cref="Body"/> in 3D space. + /// </summary> + public Vector4d Position + { + get { return position; } + } + + /// <summary> + /// Whether to record previous positions of this instance, to render an orbit tracer behind it. + /// </summary> + public bool RecordPreviousPositions { get; set; } + + /// <summary> + /// The current velocity of the <see cref="Body"/> in 3D space. + /// </summary> + public Vector4d Velocity + { + get { return velocity; } + } + + /// <summary> + /// Gets the force vector for the attraction between <see cref="Body"/> A and <see cref="Body"/> B. + /// </summary> + /// <param name="a">The first <see cref="Body"/> instance.</param> + /// <param name="b">The second <see cref="Body"/> instance.</param> + /// <returns></returns> + public static Vector4d GetForceBetween(Body a, Body b) + { + // Inlines the Body.DistanceTo(Body) as the position deltas need to be cached for later, + // as well as to gain a small performance increase + double dx = b.Position.X - a.Position.X, + dy = b.Position.Y - a.Position.Y, + dz = b.Position.Z - a.Position.Z; + + // The distance between two bodies can be found via taking the magnitude of their displacements, + // as shown here via pythagoras + double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz); + + double numerator = Constants.G * a.Mass * b.Mass; + double denominator = distance * distance + Constants.SofteningFactor2; + + // Using the equation Force = Gravitational Constant * Mass(a) * Mass(b) / distance(a, b)^2 + // with a softening factor, we get the attraction force vector between the 2 bodies + double force = numerator / denominator; + + return new Vector4d(force * dx / distance, force * dy / distance, force * dz / distance); + } + + /// <summary> + /// Calculates the force between this instance and the given other body, and adds the resultant vector to the + /// internal total force vector. + /// </summary> + /// <param name="otherBody">The other body to calculate the force between.</param> + public void AddForce(Body otherBody) + { + force += GetForceBetween(this, otherBody); + } + + /// <summary> + /// Collides this instance with the given <see cref="Body"/> instance. + /// </summary> + /// <param name="otherBody">The other instance with which to collide.</param> + public void Collide(Body otherBody) + { + mass += otherBody.Mass; + velocity += otherBody.Velocity; + } + + /// <summary> + /// Finds and returns the distance between the current <see cref="Body"/> instance and the given <see cref="Body"/>. + /// In other words, it finds the magnitude of the translation vector between the two <see cref="Body"/> instances. + /// </summary> + /// <param name="body">The other <see cref="Body"/> instance to which to calculate the distance.</param> + /// <param name="displacement">The vector showing the displacement of the current body from the given one.</param> + /// <returns>The distance to the other <see cref="Body"/> as a <see cref="float"/>.</returns> + public double DistanceTo(Body body, out Vector4d displacement) + { + double dpx = body.Position.X - Position.X, + dpy = body.Position.Y - Position.Y, + dpz = body.Position.Z - Position.Z; + + displacement = new Vector4d(dpx, dpy, dpz); + + return Math.Sqrt(dpx * dpx + dpy * dpy + dpz * dpz); + } + + /// <summary> + /// Resets the internal force vector. + /// </summary> + public void ResetForce() + { + force.X = 0; + force.Y = 0; + force.Z = 0; + } + + /// <summary> + /// Updates the <see cref="Position"/> of the current body using the internal force vector and the given time step. + /// </summary> + /// <param name="deltaTime">The time step.</param> + public void Update(double deltaTime) + { + velocity += deltaTime * force / mass; + + if (RecordPreviousPositions) + { + orbitTracer.Enqueue(position); + } + + position += deltaTime * velocity; + } + + /// <summary> + /// Updates the <see cref="Position"/> of the current body using the given force vector and time step. + /// </summary> + /// <param name="forceVector">The sum vector of all forces due to other <see cref="Body"/>s.</param> + /// <param name="deltaTime">The time step.</param> + public void Update(Vector4d forceVector, double deltaTime) + { + velocity += deltaTime * forceVector / mass; + + if (RecordPreviousPositions) + { + orbitTracer.Enqueue(position); + } + + position += deltaTime * velocity; + } + + #region Overrides of Object + + /// <inheritdoc /> + public override string ToString() + { + return string.Format(BodyFormatString, Generation, Id, Position, Velocity, Mass); + } + + #endregion Overrides of Object + } +} +\ No newline at end of file diff --git a/StarSim/StarSimLib/Data Structures/EulerAngle.cs b/StarSim/StarSimLib/Data Structures/EulerAngle.cs @@ -0,0 +1,36 @@ +namespace StarSimLib.Data_Structures +{ + /// <summary> + /// Represents a set of 3 angles, that together describe a 3D rotation. + /// </summary> + public struct EulerAngle + { + /// <summary> + /// Angle of rotation in the x axis. + /// </summary> + public double X; + + /// <summary> + /// Angle of rotation in the y axis. + /// </summary> + public double Y; + + /// <summary> + /// Angle of rotation in the z axis. + /// </summary> + public double Z; + + /// <summary> + /// Initialises a new instance of the <see cref="EulerAngle"/> struct. + /// </summary> + /// <param name="x">The angle of rotation in the x axis.</param> + /// <param name="y">The angle of rotation in the y axis.</param> + /// <param name="z">The angle of rotation in the z axis.</param> + public EulerAngle(double x, double y, double z) + { + X = x; + Y = y; + Z = z; + } + } +} +\ No newline at end of file diff --git a/StarSim/StarSimLib/Data Structures/EulerAngles.cs b/StarSim/StarSimLib/Data Structures/EulerAngles.cs @@ -1,36 +0,0 @@ -namespace StarSimLib.Data_Structures -{ - /// <summary> - /// Represents a set of 3 angles, that together describe a 3D rotation. - /// </summary> - public struct EulerAngles - { - /// <summary> - /// Angle of rotation in the x axis. - /// </summary> - public double X; - - /// <summary> - /// Angle of rotation in the y axis. - /// </summary> - public double Y; - - /// <summary> - /// Angle of rotation in the z axis. - /// </summary> - public double Z; - - /// <summary> - /// Initialises a new instance of the <see cref="EulerAngles"/> struct. - /// </summary> - /// <param name="x">The angle of rotation in the x axis.</param> - /// <param name="y">The angle of rotation in the y axis.</param> - /// <param name="z">The angle of rotation in the z axis.</param> - public EulerAngles(double x, double y, double z) - { - X = x; - Y = y; - Z = z; - } - } -} -\ No newline at end of file diff --git a/StarSim/StarSimLib/Data Structures/OrbitTracer.cs b/StarSim/StarSimLib/Data Structures/OrbitTracer.cs @@ -0,0 +1,93 @@ +using System.Collections.Generic; +using StarSimLib.Physics; + +namespace StarSimLib.Data_Structures +{ + /// <summary> + /// Represents a series of points denoting the previous positions of a <see cref="Body"/> instance. Used to render + /// an orbit tracer behind the <see cref="Body"/>. + /// </summary> + public class OrbitTracer + { + /// <summary> + /// Sample rate for the previous position. Used to improve performance and get a longer orbit tracer tail + /// for less computation. The previous position will be saved once every 20 sampling opportunities. + /// </summary> + private const int PositionSampleRate = 20; + + /// <summary> + /// Backing field for the <see cref="PreviousPositions"/> property. + /// </summary> + private readonly Queue<Vector4d> previousPositions; + + /// <summary> + /// Due to the <see cref="Queue{T}"/>s inability to fetch the second-to-last element, we must explicitly + /// cache it in order to use it in interpolation calculations later. + /// </summary> + private Vector4d dequeuedPosition; + + /// <summary> + /// Counts the number of sampling opportunities that have gone by since the last position sample. Resets once + /// it reaches the value of <see cref="PositionSampleRate"/>. + /// </summary> + private int positionSampleCounter; + + /// <summary> + /// Initialises a new instance of the <see cref="OrbitTracer"/> class. + /// </summary> + public OrbitTracer() + { + previousPositions = new Queue<Vector4d>(Constants.StoredPreviousPositionCount); + } + + /// <summary> + /// An <see cref="Queue{T}"/> containing previous <see cref="Vector4d"/> positions of the body. + /// </summary> + public ref readonly Queue<Vector4d> PreviousPositions + { + get { return ref previousPositions; } + } + + /// <summary> + /// Clears the <see cref="Queue{T}"/> holding the previous positions. + /// </summary> + public void Clear() + { + previousPositions.Clear(); + } + + /// <summary> + /// Enqueues the current position on the <see cref="previousPositions"/> queue, to save it. + /// Will dequeue positions from the queue if the number of stored positions exceeds the + /// value in <see cref="Constants.StoredPreviousPositionCount"/>. Will only enqueue the + /// current position if the <see cref="PositionSampleRate"/> is met. + /// </summary> + public void Enqueue(Vector4d position) + { + // if the sample rate limit has not yet been met, don't sample a position but instead edit the last stored + // position using linear interpolation to give a smooth shrinking motion + if (++positionSampleCounter < PositionSampleRate) + { + /* + double interpolationPercentage = positionSampleCounter / (float)PositionSampleRate; + + previousPositions[0].X = (1 - interpolationPercentage) * previousPositions[0].X + interpolationPercentage * previousPositions[1].X; + previousPositions[0].Y = (1 - interpolationPercentage) * previousPositions[0].Y + interpolationPercentage * previousPositions[1].Y; + previousPositions[0].Z = (1 - interpolationPercentage) * previousPositions[0].Z + interpolationPercentage * previousPositions[1].Z; + */ + + return; + } + + previousPositions.Enqueue(position); + + if (previousPositions.Count >= Constants.StoredPreviousPositionCount) + { + dequeuedPosition = previousPositions.Dequeue(); + } + + // reset the counter + positionSampleCounter = 0; + } + } +} +\ No newline at end of file diff --git a/StarSim/StarSimLib/Graphics/Drawer.cs b/StarSim/StarSimLib/Graphics/Drawer.cs @@ -123,7 +123,7 @@ namespace StarSimLib.Graphics /// <summary> /// The 3D rotation. /// </summary> - private EulerAngles rotation; + private EulerAngle rotation; /// <summary> /// The rotation matrix for the x axis. @@ -340,7 +340,7 @@ namespace StarSimLib.Graphics // otherwise, we skip the relatively expensive rendering code if (body.RecordPreviousPositions) { - Vector4d[] orbitTracerPositions = body.PreviousPositions.ToArray(); + Vector4d[] orbitTracerPositions = body.OrbitTracer.PreviousPositions.ToArray(); for (uint i = 0; i < orbitTracerPositions.Length; i++) { @@ -415,7 +415,7 @@ namespace StarSimLib.Graphics "The given rotation direction was not within the valid range."); } - // once we hit 360 (or -360) degrees of rotation, we wrap back around to 0 degrees + // once we hit 360 degrees of rotation, we wrap back around to 0 degrees rotation.X %= 360; rotation.Y %= 360; rotation.Z %= 360; diff --git a/StarSim/StarSimLib/Physics/Body.cs b/StarSim/StarSimLib/Physics/Body.cs @@ -1,281 +0,0 @@ -using System; -using System.Collections.Generic; -using StarSimLib.Data_Structures; - -namespace StarSimLib.Physics -{ - /// <summary> - /// Represents a stellar body. - /// </summary> - public class Body - { - /// <summary> - /// Describes how the <see cref="Body"/> instance should be formatted as a <see cref="string"/>. - /// </summary> - private const string BodyFormatString = - "Body {0,2}.{1,-4}: Pos-{2}, Vel-{3} Mass-{4,3}"; - - /// <summary> - /// Sample rate for the previous position. Used to improve performance and get a longer orbit tracer tail - /// for less computation. The previous position will be saved once every 20 sampling opportunities. - /// </summary> - private const int PositionSampleRate = 20; - - /// <summary> - /// Backing field for the <see cref="PreviousPositions"/> property. - /// </summary> - private readonly Queue<Vector4d> previousPositions; - - /// <summary> - /// The backing field for the <see cref="Force"/> property. - /// </summary> - private Vector4d force; - - /// <summary> - /// Backing field for the <see cref="Mass"/> property. - /// </summary> - private double mass; - - /// <summary> - /// Backing field for the <see cref="Position"/> property. - /// </summary> - private Vector4d position; - - /// <summary> - /// Counts the number of sampling opportunities that have gone by since the last position sample. Resets once - /// it reaches the value of <see cref="PositionSampleRate"/>. - /// </summary> - private int positionSampleCounter = 0; - - /// <summary> - /// Backing field for the <see cref="Velocity"/> property. - /// </summary> - private Vector4d velocity; - - /// <summary> - /// The generation that this body belongs to. - /// </summary> - public readonly uint Generation; - - /// <summary> - /// The unique id for this body. - /// </summary> - public readonly uint Id; - - /// <summary> - /// Initialises a new instance of the <see cref="Body"/> class. - /// </summary> - /// <param name="position">The starting position of the <see cref="Body"/>.</param> - /// <param name="velocity">The starting velocity of the <see cref="Body"/>.</param> - /// <param name="mass">The starting mass of the <see cref="Body"/>.</param> - /// <param name="generation">The generation that this <see cref="Body"/> belongs to.</param> - /// <param name="id">The unique id for this body.</param> - public Body(Vector4d position, Vector4d velocity, double mass, uint generation = 1, uint id = 1) - { - Generation = generation; - Id = id; - - this.position = position; - this.position.W = 1; - this.velocity = velocity; - this.mass = mass; - - force = new Vector4d(); - previousPositions = new Queue<Vector4d>(Constants.StoredPreviousPositionCount + 1); - } - - /// <summary> - /// The current force on the <see cref="Body"/> in 3D space. - /// </summary> - public Vector4d Force - { - get { return force; } - } - - /// <summary> - /// The mass of the <see cref="Body"/>. - /// </summary> - public double Mass - { - get { return mass; } - } - - /// <summary> - /// The current position of the <see cref="Body"/> in 3D space. - /// </summary> - public Vector4d Position - { - get { return position; } - } - - /// <summary> - /// A <see cref="Queue{T}"/> containing previous positions of the body. - /// </summary> - public ref readonly Queue<Vector4d> PreviousPositions - { - get { return ref previousPositions; } - } - - /// <summary> - /// Whether to record previous positions of this instance, to render an orbit tracer behind it. - /// </summary> - public bool RecordPreviousPositions { get; set; } - - /// <summary> - /// The current velocity of the <see cref="Body"/> in 3D space. - /// </summary> - public Vector4d Velocity - { - get { return velocity; } - } - - /// <summary> - /// Enqueues the current position on the <see cref="previousPositions"/> queue, to save it. - /// Will dequeue positions from the queue if the number of stored positions exceeds the - /// value in <see cref="Constants.StoredPreviousPositionCount"/>. Will only enqueue the - /// current position if the <see cref="PositionSampleRate"/> is met. - /// </summary> - private void EnqueuePosition() - { - // if the sample rate limit has not yet been met, don't sample a position - if (++positionSampleCounter < PositionSampleRate) return; - - previousPositions.Enqueue(position); - - if (previousPositions.Count > Constants.StoredPreviousPositionCount) - { - previousPositions.Dequeue(); - } - - // reset the counter - positionSampleCounter = 0; - } - - /// <summary> - /// Gets the force vector for the attraction between <see cref="Body"/> A and <see cref="Body"/> B. - /// </summary> - /// <param name="a">The first <see cref="Body"/> instance.</param> - /// <param name="b">The second <see cref="Body"/> instance.</param> - /// <returns></returns> - public static Vector4d GetForceBetween(Body a, Body b) - { - // Inlines the Body.DistanceTo(Body) as the position deltas need to be cached for later, - // as well as to gain a small performance increase - double dx = b.Position.X - a.Position.X, - dy = b.Position.Y - a.Position.Y, - dz = b.Position.Z - a.Position.Z; - - // The distance between two bodies can be found via taking the magnitude of their displacements, - // as shown here via pythagoras - double distance = Math.Sqrt(dx * dx + dy * dy + dz * dz); - - double numerator = Constants.G * a.Mass * b.Mass; - double denominator = distance * distance + Constants.SofteningFactor2; - - // Using the equation Force = Gravitational Constant * Mass(a) * Mass(b) / distance(a, b)^2 - // with a softening factor, we get the attraction force vector between the 2 bodies - double force = numerator / denominator; - - return new Vector4d(force * dx / distance, force * dy / distance, force * dz / distance); - } - - /// <summary> - /// Calculates the force between this instance and the given other body, and adds the resultant vector to the - /// internal total force vector. - /// </summary> - /// <param name="otherBody">The other body to calculate the force between.</param> - public void AddForce(Body otherBody) - { - force += GetForceBetween(this, otherBody); - } - - /// <summary> - /// Clears the <see cref="Queue{T}"/> holding the previous positions. - /// </summary> - public void ClearPreviousPositionQueue() - { - previousPositions.Clear(); - } - - /// <summary> - /// Collides this instance with the given <see cref="Body"/> instance. - /// </summary> - /// <param name="otherBody">The other instance with which to collide.</param> - public void Collide(Body otherBody) - { - mass += otherBody.Mass; - velocity += otherBody.Velocity; - } - - /// <summary> - /// Finds and returns the distance between the current <see cref="Body"/> instance and the given <see cref="Body"/>. - /// In other words, it finds the magnitude of the translation vector between the two <see cref="Body"/> instances. - /// </summary> - /// <param name="body">The other <see cref="Body"/> instance to which to calculate the distance.</param> - /// <param name="displacement">The vector showing the displacement of the current body from the given one.</param> - /// <returns>The distance to the other <see cref="Body"/> as a <see cref="float"/>.</returns> - public double DistanceTo(Body body, out Vector4d displacement) - { - double dpx = body.Position.X - Position.X, - dpy = body.Position.Y - Position.Y, - dpz = body.Position.Z - Position.Z; - - displacement = new Vector4d(dpx, dpy, dpz); - - return Math.Sqrt(dpx * dpx + dpy * dpy + dpz * dpz); - } - - /// <summary> - /// Resets the internal force vector. - /// </summary> - public void ResetForce() - { - force.X = 0; - force.Y = 0; - force.Z = 0; - } - - /// <summary> - /// Updates the <see cref="Position"/> of the current body using the internal force vector and the given time step. - /// </summary> - /// <param name="deltaTime">The time step.</param> - public void Update(double deltaTime) - { - velocity += deltaTime * force / mass; - - if (RecordPreviousPositions) - { - EnqueuePosition(); - } - - position += deltaTime * velocity; - } - - /// <summary> - /// Updates the <see cref="Position"/> of the current body using the given force vector and time step. - /// </summary> - /// <param name="forceVector">The sum vector of all forces due to other <see cref="Body"/>s.</param> - /// <param name="deltaTime">The time step.</param> - public void Update(Vector4d forceVector, double deltaTime) - { - velocity += deltaTime * forceVector / mass; - - if (RecordPreviousPositions) - { - EnqueuePosition(); - } - - position += deltaTime * velocity; - } - - #region Overrides of Object - - /// <inheritdoc /> - public override string ToString() - { - return string.Format(BodyFormatString, Generation, Id, Position, Velocity, Mass); - } - - #endregion Overrides of Object - } -} -\ No newline at end of file diff --git a/StarSim/StarSimLib/StarSimLib.csproj b/StarSim/StarSimLib/StarSimLib.csproj @@ -2,16 +2,33 @@ <PropertyGroup> <TargetFramework>netstandard2.0</TargetFramework> + <Platforms>AnyCPU;x64;x86</Platforms> </PropertyGroup> <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|AnyCPU'"> <DocumentationFile>StarSimLib.xml</DocumentationFile> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x86'"> + <DocumentationFile>StarSimLib.xml</DocumentationFile> + </PropertyGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Release|x64'"> + <DocumentationFile>StarSimLib.xml</DocumentationFile> + </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|AnyCPU'"> <DocumentationFile>StarSimLib.xml</DocumentationFile> </PropertyGroup> + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x86'"> + <DocumentationFile>StarSimLib.xml</DocumentationFile> + </PropertyGroup> + + <PropertyGroup Condition="'$(Configuration)|$(Platform)'=='Debug|x64'"> + <DocumentationFile>StarSimLib.xml</DocumentationFile> + </PropertyGroup> + <ItemGroup> <PackageReference Include="Microsoft.EntityFrameworkCore" Version="2.2.4" /> <PackageReference Include="Microsoft.EntityFrameworkCore.Design" Version="2.2.4" /> diff --git a/StarSim/StarSimLib/StarSimLib.xml b/StarSim/StarSimLib/StarSimLib.xml @@ -106,29 +106,29 @@ <member name="M:StarSimLib.Contexts.SimulatorContext.OnModelCreating(Microsoft.EntityFrameworkCore.ModelBuilder)"> <inheritdoc /> </member> - <member name="T:StarSimLib.Data_Structures.EulerAngles"> + <member name="T:StarSimLib.Data_Structures.EulerAngle"> <summary> Represents a set of 3 angles, that together describe a 3D rotation. </summary> </member> - <member name="F:StarSimLib.Data_Structures.EulerAngles.X"> + <member name="F:StarSimLib.Data_Structures.EulerAngle.X"> <summary> Angle of rotation in the x axis. </summary> </member> - <member name="F:StarSimLib.Data_Structures.EulerAngles.Y"> + <member name="F:StarSimLib.Data_Structures.EulerAngle.Y"> <summary> Angle of rotation in the y axis. </summary> </member> - <member name="F:StarSimLib.Data_Structures.EulerAngles.Z"> + <member name="F:StarSimLib.Data_Structures.EulerAngle.Z"> <summary> Angle of rotation in the z axis. </summary> </member> - <member name="M:StarSimLib.Data_Structures.EulerAngles.#ctor(System.Double,System.Double,System.Double)"> + <member name="M:StarSimLib.Data_Structures.EulerAngle.#ctor(System.Double,System.Double,System.Double)"> <summary> - Initialises a new instance of the <see cref="T:StarSimLib.Data_Structures.EulerAngles"/> struct. + Initialises a new instance of the <see cref="T:StarSimLib.Data_Structures.EulerAngle"/> struct. </summary> <param name="x">The angle of rotation in the x axis.</param> <param name="y">The angle of rotation in the y axis.</param> @@ -234,6 +234,58 @@ <member name="M:StarSimLib.Data_Structures.Matrix4x4.ToString"> <inheritdoc /> </member> + <member name="T:StarSimLib.Data_Structures.OrbitTracer"> + <summary> + Represents a series of points denoting the previous positions of a <see cref="T:StarSimLib.Physics.Body"/> instance. Used to render + an orbit tracer behind the <see cref="T:StarSimLib.Physics.Body"/>. + </summary> + </member> + <member name="F:StarSimLib.Data_Structures.OrbitTracer.PositionSampleRate"> + <summary> + Sample rate for the previous position. Used to improve performance and get a longer orbit tracer tail + for less computation. The previous position will be saved once every 20 sampling opportunities. + </summary> + </member> + <member name="F:StarSimLib.Data_Structures.OrbitTracer.previousPositions"> + <summary> + Backing field for the <see cref="P:StarSimLib.Data_Structures.OrbitTracer.PreviousPositions"/> property. + </summary> + </member> + <member name="F:StarSimLib.Data_Structures.OrbitTracer.dequeuedPosition"> + <summary> + Due to the <see cref="T:System.Collections.Generic.Queue`1"/>s inability to fetch the second-to-last element, we must explicitly + cache it in order to use it in interpolation calculations later. + </summary> + </member> + <member name="F:StarSimLib.Data_Structures.OrbitTracer.positionSampleCounter"> + <summary> + Counts the number of sampling opportunities that have gone by since the last position sample. Resets once + it reaches the value of <see cref="F:StarSimLib.Data_Structures.OrbitTracer.PositionSampleRate"/>. + </summary> + </member> + <member name="M:StarSimLib.Data_Structures.OrbitTracer.#ctor"> + <summary> + Initialises a new instance of the <see cref="T:StarSimLib.Data_Structures.OrbitTracer"/> class. + </summary> + </member> + <member name="P:StarSimLib.Data_Structures.OrbitTracer.PreviousPositions"> + <summary> + An <see cref="T:System.Collections.Generic.Queue`1"/> containing previous <see cref="T:StarSimLib.Data_Structures.Vector4d"/> positions of the body. + </summary> + </member> + <member name="M:StarSimLib.Data_Structures.OrbitTracer.Clear"> + <summary> + Clears the <see cref="T:System.Collections.Generic.Queue`1"/> holding the previous positions. + </summary> + </member> + <member name="M:StarSimLib.Data_Structures.OrbitTracer.Enqueue(StarSimLib.Data_Structures.Vector4d)"> + <summary> + Enqueues the current position on the <see cref="F:StarSimLib.Data_Structures.OrbitTracer.previousPositions"/> queue, to save it. + Will dequeue positions from the queue if the number of stored positions exceeds the + value in <see cref="F:StarSimLib.Constants.StoredPreviousPositionCount"/>. Will only enqueue the + current position if the <see cref="F:StarSimLib.Data_Structures.OrbitTracer.PositionSampleRate"/> is met. + </summary> + </member> <member name="T:StarSimLib.Data_Structures.Quaternion"> <summary> Represents a rotation as a set of 4 values. @@ -707,7 +759,8 @@ <member name="M:StarSimLib.Graphics.Drawer.DrawBodies"> <summary> Draws each <see cref="T:StarSimLib.Physics.Body"/> instance that is managed by this drawer to the <see cref="T:SFML.Graphics.RenderTarget"/> specified - in the constructor. + in the constructor, using the current view settings (rotation, zoom, etc.) to project the positions from 3D to 2D. + This method should be called every frame, as without it the view isn't updated and neither are rotation or zoom. </summary> </member> <member name="M:StarSimLib.Graphics.Drawer.Rotate(StarSimLib.Graphics.RotationDirection,System.Double)"> @@ -733,15 +786,9 @@ Describes how the <see cref="T:StarSimLib.Physics.Body"/> instance should be formatted as a <see cref="T:System.String"/>. </summary> </member> - <member name="F:StarSimLib.Physics.Body.PositionSampleRate"> - <summary> - Sample rate for the previous position. Used to improve performance and get a longer orbit tracer tail - for less computation. The previous position will be saved once every 20 sampling opportunities. - </summary> - </member> - <member name="F:StarSimLib.Physics.Body.previousPositions"> + <member name="F:StarSimLib.Physics.Body.orbitTracer"> <summary> - Backing field for the <see cref="P:StarSimLib.Physics.Body.PreviousPositions"/> property. + The orbit tracers for this instance. </summary> </member> <member name="F:StarSimLib.Physics.Body.force"> @@ -759,12 +806,6 @@ Backing field for the <see cref="P:StarSimLib.Physics.Body.Position"/> property. </summary> </member> - <member name="F:StarSimLib.Physics.Body.positionSampleCounter"> - <summary> - Counts the number of sampling opportunities that have gone by since the last position sample. Resets once - it reaches the value of <see cref="F:StarSimLib.Physics.Body.PositionSampleRate"/>. - </summary> - </member> <member name="F:StarSimLib.Physics.Body.velocity"> <summary> Backing field for the <see cref="P:StarSimLib.Physics.Body.Velocity"/> property. @@ -800,14 +841,14 @@ The mass of the <see cref="T:StarSimLib.Physics.Body"/>. </summary> </member> - <member name="P:StarSimLib.Physics.Body.Position"> + <member name="P:StarSimLib.Physics.Body.OrbitTracer"> <summary> - The current position of the <see cref="T:StarSimLib.Physics.Body"/> in 3D space. + The <see cref="T:StarSimLib.Data_Structures.OrbitTracer"/> for this instance. </summary> </member> - <member name="P:StarSimLib.Physics.Body.PreviousPositions"> + <member name="P:StarSimLib.Physics.Body.Position"> <summary> - A <see cref="T:System.Collections.Generic.Queue`1"/> containing previous positions of the body. + The current position of the <see cref="T:StarSimLib.Physics.Body"/> in 3D space. </summary> </member> <member name="P:StarSimLib.Physics.Body.RecordPreviousPositions"> @@ -820,14 +861,6 @@ The current velocity of the <see cref="T:StarSimLib.Physics.Body"/> in 3D space. </summary> </member> - <member name="M:StarSimLib.Physics.Body.EnqueuePosition"> - <summary> - Enqueues the current position on the <see cref="F:StarSimLib.Physics.Body.previousPositions"/> queue, to save it. - Will dequeue positions from the queue if the number of stored positions exceeds the - value in <see cref="F:StarSimLib.Constants.StoredPreviousPositionCount"/>. Will only enqueue the - current position if the <see cref="F:StarSimLib.Physics.Body.PositionSampleRate"/> is met. - </summary> - </member> <member name="M:StarSimLib.Physics.Body.GetForceBetween(StarSimLib.Physics.Body,StarSimLib.Physics.Body)"> <summary> Gets the force vector for the attraction between <see cref="T:StarSimLib.Physics.Body"/> A and <see cref="T:StarSimLib.Physics.Body"/> B. @@ -843,11 +876,6 @@ </summary> <param name="otherBody">The other body to calculate the force between.</param> </member> - <member name="M:StarSimLib.Physics.Body.ClearPreviousPositionQueue"> - <summary> - Clears the <see cref="T:System.Collections.Generic.Queue`1"/> holding the previous positions. - </summary> - </member> <member name="M:StarSimLib.Physics.Body.Collide(StarSimLib.Physics.Body)"> <summary> Collides this instance with the given <see cref="T:StarSimLib.Physics.Body"/> instance. diff --git a/StarSim/StarSimLib/UI/InputHandler.cs b/StarSim/StarSimLib/UI/InputHandler.cs @@ -1,5 +1,6 @@ using System; using SFML.Window; +using StarSimLib.Data_Structures; using StarSimLib.Graphics; using StarSimLib.Physics; @@ -71,9 +72,9 @@ namespace StarSimLib.UI { // we want to clear the screen of any orbit tracers that still exist when we turn orbit tracing // off, so we must clear the previous position queues of every managed object. this has the - // effect of clearing the vertex arrays holding the orbit tracer vertices + // effect of clearing the vertex arrays holding the orbit tracer vertices during the next draw step body.RecordPreviousPositions = RecordOrbitTracers; - body.ClearPreviousPositionQueue(); + body.OrbitTracer.Clear(); } break; @@ -120,6 +121,14 @@ namespace StarSimLib.UI $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; break; + case Keyboard.Key.Comma: + // decrease the simulation speed + break; + + case Keyboard.Key.Period: + // increase the simulation speed + break; + default: break; }