2021-08-10 22:27:19 +02:00
// <copyright file="Locatable.cs" company="alterNERDtive">
2022-05-29 13:34:13 +02:00
// Copyright 2021– 2022 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 <https://www.gnu.org/licenses/>.
// </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 )
2021-08-22 22:43:51 +02:00
= > 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, we’ re 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 object’ s 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 ) ;
}
}
}