using System; using System.Collections.Generic; using System.Diagnostics.CodeAnalysis; using System.Runtime.Serialization; namespace Raytheon.Units { /// /// This class represents an acceleration. /// /// It has no constructors. Instead, it provides multiple methods for creating objects of this /// type. Those methods are of the form FromXXX, where XXX is a unit (e.g. /// FromMetersPerSecSqrd). /// /// Properties (e.g. FeetPerSecSqrd) are provided to convert the value to other units and return /// as type double. /// /// Methods (operator overloads) are provided to perform calculations with related types (e.g. /// Velocity, Length). /// [Serializable] [DataContract] public class Acceleration { public enum Unit { FeetPerSecSqrd, MetersPerSecSqrd, Gs } public static IDictionary> UnitAbbreviations = new Dictionary>() { {Unit.FeetPerSecSqrd, new List(){ "ft/sec^2" } }, {Unit.MetersPerSecSqrd, new List(){ "m/sec^2" } }, {Unit.Gs, new List(){ "g" } } }; private const Unit DefaultUnits = Unit.MetersPerSecSqrd; private const double FeetPerMeter = 3.280839895013123; private const double Gravity = 9.80665; // m/sec^2 [DataMember(Name = "Acceleration", IsRequired = true)] private double _acceleration; // meters/seconds^2 // map: unit => abbreviation, conversion method and property private static IDictionary> _unitInfo = new Dictionary>() { { Unit.FeetPerSecSqrd, new UnitInfo(UnitAbbreviations[Unit.FeetPerSecSqrd], FromFeetPerSecSqrd, typeof(Acceleration).GetProperty("FeetPerSecSqrd").GetGetMethod()) }, { Unit.MetersPerSecSqrd, new UnitInfo(UnitAbbreviations[Unit.MetersPerSecSqrd], FromMetersPerSecSqrd, typeof(Acceleration).GetProperty("MetersPerSecSqrd").GetGetMethod()) }, { Unit.Gs, new UnitInfo(UnitAbbreviations[Unit.Gs], FromGs, typeof(Acceleration).GetProperty("Gs").GetGetMethod()) } }; /// /// Prevents a default instance of the class from being created. /// Use FromXXX methods to create objects of this type. /// /// No one should be calling this, it is only here to prevent users from creating default object private Acceleration() { throw new InvalidOperationException("No one should be calling this, it is only here to prevent users from creating default object"); } /// /// ctor used by this class to create objects in FromXXX methods /// /// The acceleration - m/sec^2. private Acceleration(double acceleration) { _acceleration = acceleration; } #region conversion properties /// /// Returns feet/sec^2 as type double /// /// /// feet/sec^2 /// public double FeetPerSecSqrd { get { return _acceleration * FeetPerMeter; } } /// /// returns Gs as type double /// public double Gs { get { return _acceleration / Gravity; } } /// /// Returns m/sec^2 as type double /// /// /// m/sec^2 /// public double MetersPerSecSqrd { get { return _acceleration; } } #endregion #region creation methods /// /// Returns Acceleration object interpreting passed value as ft/sec^2 /// /// ft/sec^2 /// public static Acceleration FromFeetPerSecSqrd(double feetPerSecSqrd) { return new Acceleration(feetPerSecSqrd / FeetPerMeter); } /// /// Returns Acceleration object interpreting passed value as m/sec^2 /// /// m/sec^2 /// public static Acceleration FromMetersPerSecSqrd(double metersPerSecSqrd) { return new Acceleration(metersPerSecSqrd); } /// /// Returns Acceleration object interpreting passed value as m/sec^2 /// /// m/sec^2 /// public static Acceleration FromGs(double g) { return FromMetersPerSecSqrd(g * Gravity); } #endregion #region parsing public static Acceleration Parse(string s) { return Common.Parse(s, _unitInfo); } public static bool TryParse(string s, out Acceleration value) { try { value = Acceleration.Parse(s); return true; } catch (Exception) { value = null; return false; } } #endregion public override bool Equals(object obj) { Acceleration c = obj as Acceleration; return (c == null) ? false : (this._acceleration == c._acceleration); } public override int GetHashCode() { return _acceleration.GetHashCode(); } #region binary operators // not implementing %, &, |, ^, <<, >> public static Acceleration operator +(Acceleration left, Acceleration right) { if (null == left) throw new ArgumentNullException("left", "Cannot add a null Acceleration"); if (null == right) throw new ArgumentNullException("right", "Cannot add null Acceleration"); return new Acceleration(left._acceleration + right._acceleration); } public static Acceleration operator -(Acceleration left, Acceleration right) { if (null == left) throw new ArgumentNullException("left", "Cannot subtract a null Acceleration"); if (null == right) throw new ArgumentNullException("right", "Cannot subtract a null Acceleration"); return new Acceleration(left._acceleration - right._acceleration); } public static Acceleration operator *(Acceleration acceleration, double scalar) { if (null == acceleration) throw new ArgumentNullException("acceleration", "Cannot multiply a null Acceleration"); return new Acceleration(acceleration._acceleration * scalar); } public static Acceleration operator *(double scalar, Acceleration acceleration) { if (null == acceleration) throw new ArgumentNullException("acceleration", "Cannot multiply a null Acceleration"); return new Acceleration(scalar * acceleration._acceleration); } public static Acceleration operator /(Acceleration acceleration, double scalar) { if (null == acceleration) throw new ArgumentNullException("acceleration", "Cannot divide a null Acceleration"); if (0.0 == scalar) throw new DivideByZeroException("Cannot divide Acceleration by 0"); return new Acceleration(acceleration._acceleration / scalar); } #endregion #region comparison operators public static bool operator ==(Acceleration left, Acceleration right) { bool bReturn = false; if (object.ReferenceEquals(left, null)) { if (object.ReferenceEquals(right, null)) { //both are null, so we are == bReturn = true; } } else { if (!object.ReferenceEquals(left, null) && !object.ReferenceEquals(right, null)) { bReturn = left._acceleration == right._acceleration; } } return bReturn; } public static bool operator !=(Acceleration left, Acceleration right) { return !(left == right); } public static bool operator <(Acceleration left, Acceleration right) { if (null == left) throw new ArgumentNullException("left", "Cannot compare null Acceleration"); if (null == right) throw new ArgumentNullException("right", "Cannot compare null Acceleration"); return left._acceleration < right._acceleration; } public static bool operator >(Acceleration left, Acceleration right) { if (null == left) throw new ArgumentNullException("left", "Cannot compare null Acceleration"); if (null == right) throw new ArgumentNullException("right", "Cannot compare null Acceleration"); return left._acceleration > right._acceleration; } public static bool operator <=(Acceleration left, Acceleration right) { if (null == left) throw new ArgumentNullException("left", "Cannot compare null Acceleration"); if (null == right) throw new ArgumentNullException("right", "Cannot compare null Acceleration"); return left._acceleration <= right._acceleration; } public static bool operator >=(Acceleration left, Acceleration right) { if (null == left) throw new ArgumentNullException("left", "Cannot compare null Acceleration"); if (null == right) throw new ArgumentNullException("right", "Cannot compare null Acceleration"); return left._acceleration >= right._acceleration; } #endregion #region operators with other classes /// /// Implements the operator * for Velocity = Acceleration * Time /// /// The acceleration. /// The time. /// /// Velocity /// public static Velocity operator *(Acceleration acceleration, PrecisionTimeSpan time) { if (null == acceleration) throw new ArgumentNullException("acceleration", "Cannot multiply with null Acceleration"); if (null == time) throw new ArgumentNullException("time", "Cannot multiply with null PrecisionTimeSpan"); return Velocity.FromMetersPerSec(acceleration.MetersPerSecSqrd * time.Seconds); } /// /// Implements the operator * for Velocity = Time * Acceleration /// /// The acceleration. /// The time. /// /// Velocity /// public static Velocity operator *(PrecisionTimeSpan time, Acceleration acceleration) { if (null == acceleration) throw new ArgumentNullException("acceleration", "Cannot multiply with null Acceleration"); if (null == time) throw new ArgumentNullException("time", "Cannot multiply with null PrecisionTimeSpan"); return Velocity.FromMetersPerSec(acceleration.MetersPerSecSqrd * time.Seconds); } #endregion /// /// Returns a string appended with default units (e.g. "1.23 m/sec^2"). /// /// /// A string that represents this instance /// public override string ToString() { return ToString(DefaultUnits); } /// /// overload that returns a string appended with specified units (e.g. "1.23 ft/sec^2"). /// /// /// public string ToString(Unit units) { double value = (double)_unitInfo[units].PropertyGetter.Invoke(this, null); return $"{value} {_unitInfo[units].Abbreviation[0]}"; } } }