EDNA/Edna/Locatable.cs

212 lines
8.1 KiB
C#
Raw Permalink Normal View History

2021-08-10 22:27:19 +02:00
// <copyright file="Locatable.cs" company="alterNERDtive">
2022-05-29 13:34:13 +02:00
// Copyright 20212022 alterNERDtive.
2021-08-10 22:27:19 +02:00
//
// This file is part of EDNA.
//
// EDNA is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, either version 3 of the License, or
// (at your option) any later version.
//
// EDNA is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// You should have received a copy of the GNU General Public License
// along with EDNA. If not, see &lt;https://www.gnu.org/licenses/&gt;.
// </copyright>
using System;
namespace alterNERDtive.Edna
{
/// <summary>
/// A location in the galaxy, represented by coordinates and a value for
/// precision (all in ly).
/// </summary>
[System.Diagnostics.CodeAnalysis.SuppressMessage("StyleCop.CSharp.DocumentationRules", "SA1649:File name should match first type name", Justification = "Either this or wrong class/struct order 🤷")]
2022-02-15 13:22:59 +01:00
public struct Coordinates
2021-08-10 22:27:19 +02:00
{
/// <summary>
2022-02-15 13:22:59 +01:00
/// Initializes a new instance of the <see cref="Coordinates"/> struct.
2021-08-10 22:27:19 +02:00
/// </summary>
/// <param name="x">The x coordinate.</param>
/// <param name="y">The y coordinate.</param>
/// <param name="z">The z coordinate.</param>
/// <param name="precision">The available precision.</param>
2022-02-15 13:22:59 +01:00
public Coordinates(double x, double y, double z, int precision)
2022-01-20 16:10:10 +01:00
=> (this.X, this.Y, this.Z, this.Precision) = (x, y, z, precision);
2021-08-10 22:27:19 +02:00
/// <summary>
2022-02-15 13:22:59 +01:00
/// Initializes a new instance of the <see cref="Coordinates"/> struct.
2021-08-10 22:27:19 +02:00
/// </summary>
/// <param name="x">The x coordinate.</param>
/// <param name="y">The y coordinate.</param>
/// <param name="z">The z coordinate.</param>
2022-02-15 13:22:59 +01:00
public Coordinates(double x, double y, double z)
2022-01-20 16:10:10 +01:00
=> (this.X, this.Y, this.Z, this.Precision) = (x, y, z, 0);
/// <summary>
2022-02-15 13:22:59 +01:00
/// Initializes a new instance of the <see cref="Coordinates"/> struct.
2022-01-20 16:10:10 +01:00
/// </summary>
2022-02-15 13:22:59 +01:00
/// <param name="edtsSystem">An EDTS system/location to convert.</param>
public Coordinates(Edts.StarSystem edtsSystem)
=> (this.X, this.Y, this.Z, this.Precision)
= ((int)edtsSystem.Position.X, (int)edtsSystem.Position.Y, (int)edtsSystem.Position.Z, (int)edtsSystem.Uncertainty);
2021-08-10 22:27:19 +02:00
2022-02-15 21:16:20 +01:00
/// <summary>
/// Initializes a new instance of the <see cref="Coordinates"/> struct.
/// </summary>
/// <param name="edsmSystem">An EDSM system to convert.</param>
public Coordinates(Edsm.ApiSystem edsmSystem)
=> (this.X, this.Y, this.Z, this.Precision)
= (edsmSystem.Coords.Value.X, edsmSystem.Coords.Value.Y, edsmSystem.Coords.Value.Z, 0);
2022-05-29 17:33:16 +02:00
/// <summary>
/// Initializes a new instance of the <see cref="Coordinates"/> struct.
/// </summary>
/// <param name="edsmCoords">A set of EDSM coordinates to convert.</param>
public Coordinates(Edsm.Coordinates edsmCoords)
=> (this.X, this.Y, this.Z, this.Precision)
= (edsmCoords.X, edsmCoords.Y, edsmCoords.Z, 0);
2021-08-10 22:27:19 +02:00
/// <summary>
/// Gets the x coordinate.
/// </summary>
public double X { get; }
/// <summary>
/// Gets the y coordinate.
/// </summary>
public double Y { get; }
/// <summary>
/// Gets the z coordinate.
/// </summary>
public double Z { get; }
/// <summary>
2021-08-22 22:27:40 +02:00
/// Gets the precision to which the location can be calculated. This is
/// an actual ± for distance, not a precision _per axis_ as for a Location.
2021-08-10 22:27:19 +02:00
/// </summary>
public int Precision { get; }
2022-02-15 13:22:59 +01:00
public static bool operator ==(Coordinates a, Coordinates b)
=> a.X == b.X && a.Y == b.Y && a.Z == b.Z && a.Precision == 0 && b.Precision == 0;
2021-08-10 22:27:19 +02:00
2022-02-15 13:22:59 +01:00
public static bool operator !=(Coordinates a, Coordinates b)
2021-08-10 22:27:19 +02:00
=> !(a == b);
/// <inheritdoc/>
public override bool Equals(object o)
2022-02-15 13:22:59 +01:00
=> o is Coordinates location && this == location;
2021-08-10 22:27:19 +02:00
/// <inheritdoc/>
public override int GetHashCode()
{
return Tuple.Create(this.X, this.Y, this.Z, this.Precision).GetHashCode();
}
/// <summary>
/// The distance to another location.
/// </summary>
/// <param name="location">The other location.</param>
/// <returns>The distance between both locations.</returns>
2022-02-15 13:22:59 +01:00
public Distance DistanceTo(Coordinates location)
2021-08-10 22:27:19 +02:00
{
2022-01-20 16:10:10 +01:00
if (this == location && this.Precision == 0)
2021-08-10 22:27:19 +02:00
{
2022-01-20 16:10:10 +01:00
return new Distance(value: 0);
2021-08-10 22:27:19 +02:00
}
else
{
2021-08-22 22:27:40 +02:00
// Precision actually adds up weird. Since Location precision is
// per each individual axis, not a radius, were dealing with a
// cube, not a sphere.
//
// Therefore for a precision p the system can be √(p²+p²+p²) =
// √(3p²) = √3*p light years from the exact coordinates.
//
// For a distance between two Locations with precision p,q these
// add up as √3(p+q). This is only the worst case scenario and
// can be less depending on the angle, but worst case is fine
// here.
2021-08-10 22:27:19 +02:00
return new Distance(
value: Math.Sqrt(
Math.Pow(this.X - location.X, 2)
+ Math.Pow(this.Y - location.Y, 2)
+ Math.Pow(this.Z - location.Z, 2)),
2021-08-22 22:27:40 +02:00
precision: (int)Math.Ceiling(Math.Sqrt(3) * (this.Precision + location.Precision)));
2021-08-10 22:27:19 +02:00
}
}
}
/// <summary>
/// A distance between two objects in the galaxy, represented by the
/// distance itself and a value for precision.
/// </summary>
public struct Distance
{
/// <summary>
/// Initializes a new instance of the <see cref="Distance"/> struct.
/// </summary>
/// <param name="value">The distance, with absolute precision.</param>
public Distance(double value)
2022-01-20 16:10:10 +01:00
: this(value: value, precision: 0)
2021-08-10 22:27:19 +02:00
{
}
/// <summary>
/// Initializes a new instance of the <see cref="Distance"/> struct.
/// </summary>
/// <param name="value">The distance.</param>
/// <param name="precision">The available precision.</param>
public Distance(double value, int precision)
{
(this.Value, this.Precision) = (value, precision);
}
/// <summary>
/// Gets the distance value in ly.
/// </summary>
public double Value { get; }
/// <summary>
/// Gets the available precision in ly.
/// </summary>
public double Precision { get; }
}
/// <summary>
/// An object that can be located in the galaxy.
/// </summary>
public abstract class Locatable
{
/// <summary>
/// Gets the objects location in the galaxy.
/// </summary>
2022-02-15 13:22:59 +01:00
public Coordinates Coordinates { get; private set; }
2021-08-10 22:27:19 +02:00
/// <summary>
/// The distance to another Locatable object.
/// </summary>
/// <param name="locatable">The other Locatable object.</param>
/// <returns>The distance between both objects.</returns>
public Distance DistanceTo(Locatable locatable)
{
return this.Coordinates.DistanceTo(locatable.Coordinates);
}
/// <summary>
/// The distance to a given Location.
/// </summary>
/// <param name="location">The Location to compare to.</param>
/// <returns>The distance to said Location.</returns>
2022-02-15 13:22:59 +01:00
public Distance DistanceTo(Coordinates location)
2021-08-10 22:27:19 +02:00
{
return this.Coordinates.DistanceTo(location);
}
}
}