StarSim

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

commit 998f16dd6aef77607c0fc3118f889f5d30d2de60
parent b1cf594f1f6ee0b9b8e285958926196627112457
Author: Mikolaj Lenczewski <33129490+EnderRifter@users.noreply.github.com>
Date:   Mon,  1 Jul 2019 21:33:43 +0100

Added initial orbit tracing until a proper solution can be found.

Diffstat:
MStarSim/StarSim/Program.cs | 206++++---------------------------------------------------------------------------
MStarSim/StarSimLib/Constants.cs | 4++--
AStarSim/StarSimLib/Data Structures/EulerAngles.cs | 37+++++++++++++++++++++++++++++++++++++
MStarSim/StarSimLib/Graphics/Drawer.cs | 119++++++++++++++++++++++++++++++++++++++++++++++++-------------------------------
MStarSim/StarSimLib/Physics/Body.cs | 28+++++++++++++++++++++++-----
MStarSim/StarSimLib/StarSimLib.xml | 136+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
MStarSim/StarSimLib/UI/InputHandler.cs | 161++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-
7 files changed, 421 insertions(+), 270 deletions(-)

diff --git a/StarSim/StarSim/Program.cs b/StarSim/StarSim/Program.cs @@ -68,201 +68,11 @@ namespace StarSim bodyPositionUpdater = BodyUpdater.UpdateBodiesBruteForce; #endif bodyDrawer = new Drawer(window, ref bodies, ref bodyShapeMap); - inputHandler = new InputHandler(); + inputHandler = new InputHandler(ref bodyDrawer); Rng = new Random(); } /// <summary> - /// Whether the simulation is paused at any given time. - /// </summary> - private static bool IsSimulationPaused { get; set; } - - /// <summary> - /// Handles key presses. - /// </summary> - /// <param name="sender">The <see cref="Window"/> that sent the event.</param> - /// <param name="eventArgs">The <see cref="KeyEventArgs"/> associated with the key press.</param> - private static void HandleKeyPressed(object sender, KeyEventArgs eventArgs) - { - string msg = ""; - - switch (eventArgs.Code) - { - case Keyboard.Key.Space: - // toggle the paused state - IsSimulationPaused = !IsSimulationPaused; - break; - - case Keyboard.Key.W: - // rotate the view north - bodyDrawer.Rotate(RotationDirection.North, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the x axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.A: - // rotate the view west - bodyDrawer.Rotate(RotationDirection.West, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} degrees clockwise in the y axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.S: - // rotate the view south - bodyDrawer.Rotate(RotationDirection.South, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} degrees clockwise in the x axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.D: - // rotate the view east - bodyDrawer.Rotate(RotationDirection.East, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the y axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.Q: - // rotate the view anti-clockwise - bodyDrawer.Rotate(RotationDirection.Anticlockwise, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the z axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.E: - // rotate the view clockwise - bodyDrawer.Rotate(RotationDirection.Clockwise, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the z axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - default: - break; - } - - if (!msg.Equals("")) - { - Console.WriteLine(msg); - } - } - - /// <summary> - /// Handles key releases. - /// </summary> - /// <param name="sender">The <see cref="Window"/> that sent the event.</param> - /// <param name="eventArgs">The <see cref="KeyEventArgs"/> associated with the key press.</param> - private static void HandleKeyReleased(object sender, KeyEventArgs eventArgs) - { - string msg = ""; - - switch (eventArgs.Code) - { - case Keyboard.Key.Space: - // toggle the paused state - IsSimulationPaused = !IsSimulationPaused; - break; - - case Keyboard.Key.W: - // rotate the view north - bodyDrawer.Rotate(RotationDirection.North, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} anticlockwise in the x axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.A: - // rotate the view west - bodyDrawer.Rotate(RotationDirection.West, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} clockwise in the y axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.S: - // rotate the view south - bodyDrawer.Rotate(RotationDirection.South, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} clockwise in the x axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.D: - // rotate the view east - bodyDrawer.Rotate(RotationDirection.East, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} anticlockwise in the y axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.Q: - // rotate the view anti-clockwise - bodyDrawer.Rotate(RotationDirection.Anticlockwise, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} anticlockwise in the z axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - case Keyboard.Key.E: - // rotate the view clockwise - bodyDrawer.Rotate(RotationDirection.Clockwise, Constants.EulerRotationStep); - msg = $"Rotated by {Constants.EulerRotationStep} anticlockwise in the z axis. " + - $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; - break; - - default: - break; - } - - if (!msg.Equals("")) - { - Console.WriteLine(msg); - } - } - - /// <summary> - /// Handles motions of the mouse. - /// </summary> - /// <param name="sender">The <see cref="Window"/> that sent the event.</param> - /// <param name="eventArgs">The <see cref="MouseMoveEventArgs"/> associated with the key press.</param> - private static void HandleMouseMoved(object sender, MouseMoveEventArgs eventArgs) - { - Console.WriteLine($"Mouse moved: {eventArgs.X} {eventArgs.Y}"); - } - - /// <summary> - /// Handles key presses of the mouse. - /// </summary> - /// <param name="sender">The <see cref="Window"/> that sent the event.</param> - /// <param name="eventArgs">The <see cref="MouseButtonEventArgs"/> associated with the key press.</param> - private static void HandleMousePressed(object sender, MouseButtonEventArgs eventArgs) - { - Console.WriteLine($"Mouse pressed: {eventArgs.X} {eventArgs.Y}, {eventArgs.Button}"); - } - - /// <summary> - /// Handles key releases of the mouse. - /// </summary> - /// <param name="sender">The <see cref="Window"/> that sent the event.</param> - /// <param name="eventArgs">The <see cref="MouseButtonEventArgs"/> associated with the key press.</param> - private static void HandleMouseReleased(object sender, MouseButtonEventArgs eventArgs) - { - Console.WriteLine($"Mouse released: {eventArgs.X} {eventArgs.Y}, {eventArgs.Button}"); - } - - /// <summary> - /// Handles scrolling of the mouse wheel. - /// </summary> - /// <param name="sender">The <see cref="Window"/> that sent the event.</param> - /// <param name="eventArgs">The <see cref="MouseWheelScrollEventArgs"/> associated with the key press.</param> - private static void HandleMouseScrolled(object sender, MouseWheelScrollEventArgs eventArgs) - { - if (eventArgs.Delta > 0) - { - bodyDrawer.Scale(1 + Constants.ZoomStep); - } - else if (eventArgs.Delta < 0) - { - bodyDrawer.Scale(1 - Constants.ZoomStep); - } - - Console.WriteLine($"Current field of view (zoom level): {bodyDrawer.FOV} ({bodyDrawer.ZoomLevel})"); - } - - /// <summary> /// Entry point for our application. /// </summary> /// <param name="args">Any command line arguments passed to the program.</param> @@ -281,12 +91,12 @@ namespace StarSim window.Closed += (sender, eventArgs) => ((RenderWindow)sender).Close(); // we apply event handlers to allow for interactivity inside the window - window.KeyPressed += HandleKeyPressed; - //window.KeyReleased += HandleKeyReleased; - window.MouseButtonPressed += HandleMousePressed; - window.MouseButtonReleased += HandleMouseReleased; - //window.MouseMoved += HandleMouseMoved; - window.MouseWheelScrolled += HandleMouseScrolled; + window.KeyPressed += inputHandler.HandleKeyPressed; + //window.KeyReleased += inputHandler.HandleKeyReleased; + window.MouseButtonPressed += inputHandler.HandleMousePressed; + window.MouseButtonReleased += inputHandler.HandleMouseReleased; + //window.MouseMoved += inputHandler.HandleMouseMoved; + window.MouseWheelScrolled += inputHandler.HandleMouseScrolled; bodyDrawer.DrawBodies(); @@ -295,7 +105,7 @@ namespace StarSim window.Clear(); window.DispatchEvents(); - if (!IsSimulationPaused) + if (!inputHandler.IsSimulationPaused) { bodyPositionUpdater(bodies, Constants.TimeStep); } diff --git a/StarSim/StarSimLib/Constants.cs b/StarSim/StarSimLib/Constants.cs @@ -10,7 +10,7 @@ namespace StarSimLib /// <summary> /// The amount of bodies that are rendered by default. /// </summary> - public const int BodyCount = 3; + public const int BodyCount = 10; /// <summary> /// The mass of the central body, if it is included. @@ -60,7 +60,7 @@ namespace StarSimLib /// <summary> /// The number of previous positions that will be stored by a body /// </summary> - public const int StoredPreviousPositionCount = 50; + public const int StoredPreviousPositionCount = 100; /// <summary> /// The time step for the simulation. diff --git a/StarSim/StarSimLib/Data Structures/EulerAngles.cs b/StarSim/StarSimLib/Data Structures/EulerAngles.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 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/Graphics/Drawer.cs b/StarSim/StarSimLib/Graphics/Drawer.cs @@ -71,6 +71,11 @@ namespace StarSimLib.Graphics private const double NearDistance = 0; /// <summary> + /// The vector by which all projected points are translated away from the camera and halfway into the view frustum. + /// </summary> + private static readonly Vector4d cameraTranslationVector = new Vector4d(0, 0, (FarDistance - NearDistance) / 2); + + /// <summary> /// The aspect ratio of the render target. Allows for normalisation of the <see cref="RenderTarget"/> space /// into a normal plane ([-1, -1] = top left, [1, 1] = bottom right), instead of having to deal with a /// variable render space. @@ -110,9 +115,9 @@ namespace StarSimLib.Graphics private Matrix4x4 projectionMatrix; /// <summary> - /// Angle of rotation in the x axis. + /// The 3D rotation. /// </summary> - private double xAngle = 0; + private EulerAngles rotation; /// <summary> /// The rotation matrix for the x axis. @@ -120,21 +125,11 @@ namespace StarSimLib.Graphics private Matrix4x4 xRotationMatrix; /// <summary> - /// Angle of rotation in the y axis. - /// </summary> - private double yAngle = 0; - - /// <summary> /// The rotation matrix for the y axis. /// </summary> private Matrix4x4 yRotationMatrix; /// <summary> - /// Angle of rotation in the z axis. - /// </summary> - private double zAngle = 0; - - /// <summary> /// The rotation matrix for the z axis. /// </summary> private Matrix4x4 zRotationMatrix; @@ -157,6 +152,7 @@ namespace StarSimLib.Graphics aspectRatio = renderTarget.Size.Y / (double)renderTarget.Size.X; + // projection and rotation matrices projectionMatrix = new Matrix4x4(new[] { new [] { aspectRatio * InverseScaleFactor, 0, 0, 0 }, @@ -189,6 +185,7 @@ namespace StarSimLib.Graphics new [] { 0d, 0, 0, 1 } }); + // set initial values for the rotation matrices UpdateRotationMatrices(); managedBodies = bodies; @@ -216,7 +213,7 @@ namespace StarSimLib.Graphics /// </summary> public double XAngle { - get { return xAngle; } + get { return rotation.X; } } /// <summary> @@ -224,7 +221,7 @@ namespace StarSimLib.Graphics /// </summary> public double YAngle { - get { return yAngle; } + get { return rotation.Y; } } /// <summary> @@ -232,7 +229,7 @@ namespace StarSimLib.Graphics /// </summary> public double ZAngle { - get { return zAngle; } + get { return rotation.Z; } } /// <summary> @@ -244,10 +241,48 @@ namespace StarSimLib.Graphics } /// <summary> + /// Projects the given <see cref="Vector4d"/> point from world space into screen space. + /// </summary> + /// <param name="point">The point to project.</param> + /// <returns>The projected point.</returns> + private Vector4d ProjectPoint(Vector4d point) + { + // rotations should happen before the point is translated into camera space + Vector4d worldSpace = point; + + // rotations of point in the x, y and z axes + worldSpace *= zRotationMatrix; + worldSpace *= yRotationMatrix; + worldSpace *= xRotationMatrix; + + // points must be translated into the camera space, as the camera must be some distance away from the + // world space origin (0,0,0) or else rendering breaks. the point is translated into the middle of the + // camera space (the view frustum) + Vector4d cameraSpace = worldSpace + cameraTranslationVector; + + // project the point position from camera space into screen space (without any special transformations) + Vector4d projectedPosition = cameraSpace * projectionMatrix; + + if (!projectedPosition.W.Equals(0)) + { + projectedPosition.X /= projectedPosition.W; + projectedPosition.Y /= projectedPosition.W; + projectedPosition.Z /= projectedPosition.W; + } + + // any transformations can be applied now + Vector4d screenPosition = projectedPosition; + + return screenPosition; + } + + /// <summary> /// Updates the rotation matrices for the view. /// </summary> private void UpdateRotationMatrices() { + (double xAngle, double yAngle, double zAngle) = (rotation.X, rotation.Y, rotation.Z); + // update the rotation matrix values for the x axis xRotationMatrix[1, 1] = Math.Cos(xAngle * DegToRad); xRotationMatrix[1, 2] = -Math.Sin(xAngle * DegToRad); @@ -279,31 +314,23 @@ namespace StarSimLib.Graphics // which is used as the new position of the shape CircleShape shape = managedBodyShapeMap[body]; - // rotations should happen before the body is translated into camera space - Vector4d worldSpace = body.Position; - - // rotations of points in the x, y and z axes - worldSpace *= zRotationMatrix; - worldSpace *= yRotationMatrix; - worldSpace *= xRotationMatrix; - - // bodies must be translated into the camera space, as the camera must be some distance away from the - // world space origin (0,0,0) or else rendering breaks. the bodies are translated into the middle of - // camera space. - Vector4d cameraSpace = worldSpace + new Vector4d(0, 0, (FarDistance - NearDistance) / 2); - - // project the body position from camera space into screen space (without any special transformations) - Vector4d projectedPosition = cameraSpace * projectionMatrix; - - if (!projectedPosition.W.Equals(0)) + foreach (Vector4d previousPosition in body.PreviousPositions) { - projectedPosition.X /= projectedPosition.W; - projectedPosition.Y /= projectedPosition.W; - projectedPosition.Z /= projectedPosition.W; + // project previous position onto the screen + Vector4d pointScreenPosition = ProjectPoint(previousPosition); + + CircleShape previousPositionShape = new CircleShape(0.5f) + { + Position = new Vector2f( + (float)(pointScreenPosition.X * renderTarget.Size.X / 2 + originOffset.X), + (float)(pointScreenPosition.Y * renderTarget.Size.Y / 2 + originOffset.Y)), + FillColor = Color.Cyan + }; + + previousPositionShape.Draw(renderTarget, RenderStates.Default); } - // any transformations can be applied now - Vector4d screenPosition = projectedPosition; + Vector4d screenPosition = ProjectPoint(body.Position); // final position shape.Position = new Vector2f( @@ -326,27 +353,27 @@ namespace StarSimLib.Graphics switch (direction) { case RotationDirection.North: - xAngle += angle % 360; + rotation.X += angle % 360; break; case RotationDirection.East: - yAngle += angle % 360; + rotation.Y += angle % 360; break; case RotationDirection.South: - xAngle -= angle % 360; + rotation.X -= angle % 360; break; case RotationDirection.West: - yAngle -= angle % 360; + rotation.Y -= angle % 360; break; case RotationDirection.Clockwise: - zAngle -= angle % 360; + rotation.Z -= angle % 360; break; case RotationDirection.Anticlockwise: - zAngle += angle % 360; + rotation.Z += angle % 360; break; default: @@ -355,9 +382,9 @@ namespace StarSimLib.Graphics } // once we hit 360 (or -360) degrees of rotation, we wrap back around to 0 degrees - xAngle %= 360; - yAngle %= 360; - zAngle %= 360; + rotation.X %= 360; + rotation.Y %= 360; + rotation.Z %= 360; UpdateRotationMatrices(); } diff --git a/StarSim/StarSimLib/Physics/Body.cs b/StarSim/StarSimLib/Physics/Body.cs @@ -16,6 +16,11 @@ namespace StarSimLib.Physics "Body {0,2}.{1,-4}: Pos-{2}, Vel-{3} Mass-{4,3}"; /// <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; @@ -31,11 +36,6 @@ namespace StarSimLib.Physics private Vector4d position; /// <summary> - /// Backing field for the <see cref="PreviousPositions"/> property. - /// </summary> - private Queue<Vector4d> previousPositions; - - /// <summary> /// Backing field for the <see cref="Velocity"/> property. /// </summary> private Vector4d velocity; @@ -69,6 +69,7 @@ namespace StarSimLib.Physics this.mass = mass; force = new Vector4d(); + previousPositions = new Queue<Vector4d>(Constants.StoredPreviousPositionCount + 1); } /// <summary> @@ -112,6 +113,21 @@ namespace StarSimLib.Physics } /// <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"/>. + /// </summary> + private void EnqueuePosition() + { + previousPositions.Enqueue(position); + + if (previousPositions.Count > Constants.StoredPreviousPositionCount) + { + previousPositions.Dequeue(); + } + } + + /// <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> @@ -194,6 +210,7 @@ namespace StarSimLib.Physics public void Update(double deltaTime) { velocity += deltaTime * force / mass; + EnqueuePosition(); position += deltaTime * velocity; } @@ -205,6 +222,7 @@ namespace StarSimLib.Physics public void Update(Vector4d forceVector, double deltaTime) { velocity += deltaTime * forceVector / mass; + EnqueuePosition(); position += deltaTime * velocity; } diff --git a/StarSim/StarSimLib/StarSimLib.xml b/StarSim/StarSimLib/StarSimLib.xml @@ -106,6 +106,34 @@ <member name="M:StarSimLib.Contexts.SimulatorContext.OnModelCreating(Microsoft.EntityFrameworkCore.ModelBuilder)"> <inheritdoc /> </member> + <member name="T:StarSimLib.Data_Structures.EulerAngles"> + <summary> + Represents a set of 3 angles, that together describe a 3D rotation. + </summary> + </member> + <member name="F:StarSimLib.Data_Structures.EulerAngles.X"> + <summary> + Angle of rotation in the x axis. + </summary> + </member> + <member name="F:StarSimLib.Data_Structures.EulerAngles.Y"> + <summary> + Angle of rotation in the y axis. + </summary> + </member> + <member name="F:StarSimLib.Data_Structures.EulerAngles.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)"> + <summary> + Initialises a new instance of the <see cref="T:StarSimLib.Data_Structures.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> + </member> <member name="T:StarSimLib.Data_Structures.Matrix4x4"> <summary> A 4-by-4 matrix of <see cref="T:System.Double"/> values. @@ -551,6 +579,11 @@ to the camera than this distance (i.e. behind the camera) are culled and not rendered. </summary> </member> + <member name="F:StarSimLib.Graphics.Drawer.cameraTranslationVector"> + <summary> + The vector by which all projected points are translated away from the camera and halfway into the view frustum. + </summary> + </member> <member name="F:StarSimLib.Graphics.Drawer.aspectRatio"> <summary> The aspect ratio of the render target. Allows for normalisation of the <see cref="T:SFML.Graphics.RenderTarget"/> space @@ -590,9 +623,9 @@ Projection matrix used for mapping from 3D to 2D. </summary> </member> - <member name="F:StarSimLib.Graphics.Drawer.xAngle"> + <member name="F:StarSimLib.Graphics.Drawer.rotation"> <summary> - Angle of rotation in the x axis. + The 3D rotation. </summary> </member> <member name="F:StarSimLib.Graphics.Drawer.xRotationMatrix"> @@ -600,21 +633,11 @@ The rotation matrix for the x axis. </summary> </member> - <member name="F:StarSimLib.Graphics.Drawer.yAngle"> - <summary> - Angle of rotation in the y axis. - </summary> - </member> <member name="F:StarSimLib.Graphics.Drawer.yRotationMatrix"> <summary> The rotation matrix for the y axis. </summary> </member> - <member name="F:StarSimLib.Graphics.Drawer.zAngle"> - <summary> - Angle of rotation in the z axis. - </summary> - </member> <member name="F:StarSimLib.Graphics.Drawer.zRotationMatrix"> <summary> The rotation matrix for the z axis. @@ -663,6 +686,13 @@ Current zoom level of the drawer. </summary> </member> + <member name="M:StarSimLib.Graphics.Drawer.ProjectPoint(StarSimLib.Data_Structures.Vector4d)"> + <summary> + Projects the given <see cref="T:StarSimLib.Data_Structures.Vector4d"/> point from world space into screen space. + </summary> + <param name="point">The point to project.</param> + <returns>The projected point.</returns> + </member> <member name="M:StarSimLib.Graphics.Drawer.UpdateRotationMatrices"> <summary> Updates the rotation matrices for the view. @@ -697,6 +727,11 @@ 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.previousPositions"> + <summary> + Backing field for the <see cref="P:StarSimLib.Physics.Body.PreviousPositions"/> property. + </summary> + </member> <member name="F:StarSimLib.Physics.Body.force"> <summary> The backing field for the <see cref="P:StarSimLib.Physics.Body.Force"/> property. @@ -712,11 +747,6 @@ Backing field for the <see cref="P:StarSimLib.Physics.Body.Position"/> property. </summary> </member> - <member name="F:StarSimLib.Physics.Body.previousPositions"> - <summary> - Backing field for the <see cref="P:StarSimLib.Physics.Body.PreviousPositions"/> property. - </summary> - </member> <member name="F:StarSimLib.Physics.Body.velocity"> <summary> Backing field for the <see cref="P:StarSimLib.Physics.Body.Velocity"/> property. @@ -767,6 +797,13 @@ 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"/>. + </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. @@ -893,5 +930,70 @@ </summary> <returns>A 3D position vector.</returns> </member> + <member name="T:StarSimLib.UI.InputHandler"> + <summary> + Provides user input handling functions. + </summary> + </member> + <member name="F:StarSimLib.UI.InputHandler.bodyDrawer"> + <summary> + The renderer used to display the <see cref="T:StarSimLib.Physics.Body"/> instances on the screen. + </summary> + </member> + <member name="M:StarSimLib.UI.InputHandler.#ctor(StarSimLib.Graphics.Drawer@)"> + <summary> + Initialises a new instance of the <see cref="T:StarSimLib.UI.InputHandler"/> class. + </summary> + <param name="drawer"> + A reference to the renderer used to display the <see cref="T:StarSimLib.Physics.Body"/> instances on the screen. + </param> + </member> + <member name="P:StarSimLib.UI.InputHandler.IsSimulationPaused"> + <summary> + Whether the simulation is paused at any given time. + </summary> + </member> + <member name="M:StarSimLib.UI.InputHandler.HandleKeyPressed(System.Object,SFML.Window.KeyEventArgs)"> + <summary> + Handles key presses. + </summary> + <param name="sender">The <see cref="T:SFML.Window.Window"/> that sent the event.</param> + <param name="eventArgs">The <see cref="T:SFML.Window.KeyEventArgs"/> associated with the key press.</param> + </member> + <member name="M:StarSimLib.UI.InputHandler.HandleKeyReleased(System.Object,SFML.Window.KeyEventArgs)"> + <summary> + Handles key releases. + </summary> + <param name="sender">The <see cref="T:SFML.Window.Window"/> that sent the event.</param> + <param name="eventArgs">The <see cref="T:SFML.Window.KeyEventArgs"/> associated with the key release.</param> + </member> + <member name="M:StarSimLib.UI.InputHandler.HandleMouseMoved(System.Object,SFML.Window.MouseMoveEventArgs)"> + <summary> + Handles motions of the mouse. + </summary> + <param name="sender">The <see cref="T:SFML.Window.Window"/> that sent the event.</param> + <param name="eventArgs">The <see cref="T:SFML.Window.MouseMoveEventArgs"/> associated with the mouse movement.</param> + </member> + <member name="M:StarSimLib.UI.InputHandler.HandleMousePressed(System.Object,SFML.Window.MouseButtonEventArgs)"> + <summary> + Handles key presses of the mouse. + </summary> + <param name="sender">The <see cref="T:SFML.Window.Window"/> that sent the event.</param> + <param name="eventArgs">The <see cref="T:SFML.Window.MouseButtonEventArgs"/> associated with the mouse press.</param> + </member> + <member name="M:StarSimLib.UI.InputHandler.HandleMouseReleased(System.Object,SFML.Window.MouseButtonEventArgs)"> + <summary> + Handles key releases of the mouse. + </summary> + <param name="sender">The <see cref="T:SFML.Window.Window"/> that sent the event.</param> + <param name="eventArgs">The <see cref="T:SFML.Window.MouseButtonEventArgs"/> associated with the mouse release.</param> + </member> + <member name="M:StarSimLib.UI.InputHandler.HandleMouseScrolled(System.Object,SFML.Window.MouseWheelScrollEventArgs)"> + <summary> + Handles scrolling of the mouse wheel. + </summary> + <param name="sender">The <see cref="T:SFML.Window.Window"/> that sent the event.</param> + <param name="eventArgs">The <see cref="T:SFML.Window.MouseWheelScrollEventArgs"/> associated with the mouse scroll.</param> + </member> </members> </doc> diff --git a/StarSim/StarSimLib/UI/InputHandler.cs b/StarSim/StarSimLib/UI/InputHandler.cs @@ -1,4 +1,9 @@ -namespace StarSimLib.UI +using System; +using SFML.Window; +using StarSimLib.Graphics; +using StarSimLib.Physics; + +namespace StarSimLib.UI { /// <summary> /// Provides user input handling functions. @@ -6,10 +11,162 @@ public class InputHandler { /// <summary> + /// The renderer used to display the <see cref="Body"/> instances on the screen. + /// </summary> + private readonly Drawer bodyDrawer; + + /// <summary> /// Initialises a new instance of the <see cref="InputHandler"/> class. /// </summary> - public InputHandler() + /// <param name="drawer"> + /// A reference to the renderer used to display the <see cref="Body"/> instances on the screen. + /// </param> + public InputHandler(ref Drawer drawer) + { + bodyDrawer = drawer; + } + + /// <summary> + /// Whether the simulation is paused at any given time. + /// </summary> + public bool IsSimulationPaused { get; set; } + + /// <summary> + /// Handles key presses. + /// </summary> + /// <param name="sender">The <see cref="Window"/> that sent the event.</param> + /// <param name="eventArgs">The <see cref="KeyEventArgs"/> associated with the key press.</param> + public void HandleKeyPressed(object sender, KeyEventArgs eventArgs) + { + string msg = ""; + + switch (eventArgs.Code) + { + case Keyboard.Key.Space: + // toggle the paused state + IsSimulationPaused = !IsSimulationPaused; + break; + + case Keyboard.Key.W: + // rotate the view north + bodyDrawer.Rotate(RotationDirection.North, Constants.EulerRotationStep); + msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the x axis. " + + $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; + break; + + case Keyboard.Key.A: + // rotate the view west + bodyDrawer.Rotate(RotationDirection.West, Constants.EulerRotationStep); + msg = $"Rotated by {Constants.EulerRotationStep} degrees clockwise in the y axis. " + + $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; + break; + + case Keyboard.Key.S: + // rotate the view south + bodyDrawer.Rotate(RotationDirection.South, Constants.EulerRotationStep); + msg = $"Rotated by {Constants.EulerRotationStep} degrees clockwise in the x axis. " + + $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; + break; + + case Keyboard.Key.D: + // rotate the view east + bodyDrawer.Rotate(RotationDirection.East, Constants.EulerRotationStep); + msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the y axis. " + + $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; + break; + + case Keyboard.Key.Q: + // rotate the view anti-clockwise + bodyDrawer.Rotate(RotationDirection.Anticlockwise, Constants.EulerRotationStep); + msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the z axis. " + + $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; + break; + + case Keyboard.Key.E: + // rotate the view clockwise + bodyDrawer.Rotate(RotationDirection.Clockwise, Constants.EulerRotationStep); + msg = $"Rotated by {Constants.EulerRotationStep} degrees anticlockwise in the z axis. " + + $"View Rotation: ({bodyDrawer.XAngle},{bodyDrawer.YAngle},{bodyDrawer.ZAngle})"; + break; + + default: + break; + } + + if (!msg.Equals("")) + { + Console.WriteLine(msg); + } + } + + /// <summary> + /// Handles key releases. + /// </summary> + /// <param name="sender">The <see cref="Window"/> that sent the event.</param> + /// <param name="eventArgs">The <see cref="KeyEventArgs"/> associated with the key release.</param> + public void HandleKeyReleased(object sender, KeyEventArgs eventArgs) + { + string msg = ""; + + switch (eventArgs.Code) + { + default: + break; + } + + if (!msg.Equals("")) + { + Console.WriteLine(msg); + } + } + + /// <summary> + /// Handles motions of the mouse. + /// </summary> + /// <param name="sender">The <see cref="Window"/> that sent the event.</param> + /// <param name="eventArgs">The <see cref="MouseMoveEventArgs"/> associated with the mouse movement.</param> + public void HandleMouseMoved(object sender, MouseMoveEventArgs eventArgs) + { + Console.WriteLine($"Mouse moved: {eventArgs.X} {eventArgs.Y}"); + } + + /// <summary> + /// Handles key presses of the mouse. + /// </summary> + /// <param name="sender">The <see cref="Window"/> that sent the event.</param> + /// <param name="eventArgs">The <see cref="MouseButtonEventArgs"/> associated with the mouse press.</param> + public void HandleMousePressed(object sender, MouseButtonEventArgs eventArgs) + { + Console.WriteLine($"Mouse pressed: {eventArgs.X} {eventArgs.Y}, {eventArgs.Button}"); + } + + /// <summary> + /// Handles key releases of the mouse. + /// </summary> + /// <param name="sender">The <see cref="Window"/> that sent the event.</param> + /// <param name="eventArgs">The <see cref="MouseButtonEventArgs"/> associated with the mouse release.</param> + public void HandleMouseReleased(object sender, MouseButtonEventArgs eventArgs) + { + Console.WriteLine($"Mouse released: {eventArgs.X} {eventArgs.Y}, {eventArgs.Button}"); + } + + /// <summary> + /// Handles scrolling of the mouse wheel. + /// </summary> + /// <param name="sender">The <see cref="Window"/> that sent the event.</param> + /// <param name="eventArgs">The <see cref="MouseWheelScrollEventArgs"/> associated with the mouse scroll.</param> + public void HandleMouseScrolled(object sender, MouseWheelScrollEventArgs eventArgs) { + if (eventArgs.Delta > 0) + { + bodyDrawer.Scale(1 + Constants.ZoomStep); + } + else if (eventArgs.Delta < 0) + { + bodyDrawer.Scale(1 - Constants.ZoomStep); + } + + Console.WriteLine($"Current field of view (zoom level): {bodyDrawer.FOV} ({bodyDrawer.ZoomLevel})"); } } } \ No newline at end of file