From bd6599df615e20ba283b89dc3f9c6bc500a4da1b Mon Sep 17 00:00:00 2001 From: Michael Krisper <michael.krisper@tugraz.at> Date: Mon, 2 Oct 2017 15:53:07 +0200 Subject: [PATCH] removed GtoKG and _isMass --- VectoCommon/VectoCommon/Utils/SI.cs | 3329 ++++++++--------- VectoCommon/VectoCommon/Utils/SIUtils.cs | 859 ++--- .../OutputData/IModalDataContainer.cs | 1 - .../OutputData/SummaryDataContainer.cs | 7 +- 4 files changed, 2061 insertions(+), 2135 deletions(-) diff --git a/VectoCommon/VectoCommon/Utils/SI.cs b/VectoCommon/VectoCommon/Utils/SI.cs index fdcc631b9a..6fc55efe82 100644 --- a/VectoCommon/VectoCommon/Utils/SI.cs +++ b/VectoCommon/VectoCommon/Utils/SI.cs @@ -42,1686 +42,1651 @@ using TUGraz.VectoCommon.Exceptions; namespace TUGraz.VectoCommon.Utils { - /// <summary> - /// SI Class for Scalar Values. Converts implicitely to double and is only castable if the SI value has no units. - /// </summary> - public class Scalar : SIBase<Scalar> - { - private static readonly int[] Units = { 0, 0, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Scalar(double val) : base(val, Units) { } - - public static implicit operator double(Scalar self) - { - return self.Val; - } - - [DebuggerHidden] - public static Scalar operator +(Scalar si1, Scalar si2) - { - return Create(si1.Val + si2.Val); - } - - [DebuggerHidden] - public static Scalar operator +(Scalar si1, double si2) - { - return Create(si1.Val + si2); - } - - [DebuggerHidden] - public static Scalar operator +(double si1, Scalar si2) - { - return Create(si1 + si2.Val); - } - - [DebuggerHidden] - public static Scalar operator -(Scalar si1, Scalar si2) - { - return Create(si1.Val - si2.Val); - } - - [DebuggerHidden] - public static Scalar operator -(Scalar si1, double si2) - { - return Create(si1.Val - si2); - } - - [DebuggerHidden] - public static Scalar operator -(double si1, Scalar si2) - { - return Create(si1 - si2.Val); - } - } - - /// <summary> - /// SI Class for Newton [N]. - /// </summary> - public class Newton : SIBase<Newton> - { - private static readonly int[] Units = { 1, 1, -2, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Newton(double val) : base(val, Units) { } - - [DebuggerHidden] - public static NewtonMeter operator *(Newton newton, Meter meter) - { - return SIBase<NewtonMeter>.Create(newton.Val * meter.Value()); - } - - [DebuggerHidden] - public static Watt operator *(Newton newton, MeterPerSecond meterPerSecond) - { - return SIBase<Watt>.Create(newton.Val * meterPerSecond.Value()); - } - - [DebuggerHidden] - public static Watt operator *(MeterPerSecond meterPerSecond, Newton newton) - { - return SIBase<Watt>.Create(newton.Val * meterPerSecond.Value()); - } - } - - /// <summary> - /// SI Class for Radian [] (rad). - /// </summary> - public class Radian : SIBase<Radian> - { - private static readonly int[] Units = { 0, 0, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Radian(double val) : base(val, Units) { } - } - - /// <summary> - /// SI Class for PerSquareSecond [1/s^2]. - /// </summary> - public class PerSquareSecond : SIBase<PerSquareSecond> - { - private static readonly int[] Units = { 0, 0, -2, 0, 0, 0, 0 }; - [DebuggerHidden] - private PerSquareSecond(double val) : base(val, Units) { } - - [DebuggerHidden] - public static PerSecond operator *(PerSquareSecond perSquareSecond, Second second) - { - return SIBase<PerSecond>.Create(perSquareSecond.Val * second.Value()); - } - } - - /// <summary> - /// SI Class for Meter per square second [m/s^2]. - /// </summary> - public class MeterPerSquareSecond : SIBase<MeterPerSquareSecond> - { - private static readonly int[] Units = { 0, 1, -2, 0, 0, 0, 0 }; - - [DebuggerHidden] - private MeterPerSquareSecond(double val) : base(val, Units) { } - - /// <summary> - /// Implements the operator *. - /// </summary> - [DebuggerHidden] - public static MeterPerSecond operator *(MeterPerSquareSecond meterPerSecond, Second second) - { - return SIBase<MeterPerSecond>.Create(meterPerSecond.Val * second.Value()); - } - } - - /// <summary> - /// SI Class for Second [s]. - /// </summary> - public class Second : SIBase<Second> - { - private static readonly int[] Units = { 0, 0, 1, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Second(double val) : base(val, Units) { } - } - - /// <summary> - /// SI Class for Meter [m]. - /// </summary> - public class Meter : SIBase<Meter> - { - private static readonly int[] Units = { 0, 1, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Meter(double val) : base(val, Units) { } - - [DebuggerHidden] - public static MeterPerSecond operator /(Meter meter, Second second) - { - return SIBase<MeterPerSecond>.Create(meter.Val / second.Value()); - } - - [DebuggerHidden] - public static MeterPerSecond operator *(Meter meter, PerSecond perSecond) - { - return SIBase<MeterPerSecond>.Create(meter.Val * perSecond.Value()); - } - - /// <summary> - /// Implements the operator /. - /// </summary> - [DebuggerHidden] - public static Second operator /(Meter second, MeterPerSecond meterPerSecond) - { - return SIBase<Second>.Create(second.Val / meterPerSecond.Value()); - } - } - - /// <summary> - /// SI Class for KilogramPerMeter [kg/m]. - /// </summary> - public class KilogramPerMeter : SIBase<KilogramPerMeter> - { - private static readonly int[] Units = { 1, -1, 0, 0, 0, 0, 0 }; - [DebuggerHidden] - private KilogramPerMeter(double val) : base(val, Units) { } - } - - /// <summary> - /// SI Class for Liter per Second [l/s]. - /// </summary> - public class LiterPerSecond : SIBase<LiterPerSecond> - { - private static readonly int[] Units = { 0, 3, -1, 0, 0, 0, 0 }; - - private LiterPerSecond(double val) : base(val * 0.001, Units) { } - } - - /// <summary> - /// SI Class for Kilogram [kg]. - /// </summary> - public class Kilogram : SIBase<Kilogram> - { - private static readonly int[] Units = { 1, 0, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Kilogram(double val) : base(val, Units) { } - - [DebuggerHidden] - public static KilogramPerSecond operator /(Kilogram kg, Second second) - { - return SIBase<KilogramPerSecond>.Create(kg.Val / second.Value()); - } - - [DebuggerHidden] - public static SI operator /(Kilogram kg, Joule j) - { - return (kg as SI) / j; - } - - [DebuggerHidden] - public static Scalar operator /(Kilogram kg, Kilogram kg2) - { - return SIBase<Scalar>.Create(kg.Val / kg2.Val); - } - - [DebuggerHidden] - public static KilogramPerMeter operator /(Kilogram kg, Meter m) - { - return SIBase<KilogramPerMeter>.Create(kg.Val / m.Value()); - } - - [DebuggerHidden] - public static Newton operator *(Kilogram kg, MeterPerSquareSecond m) - { - return SIBase<Newton>.Create(kg.Val * m.Value()); - } - - [DebuggerHidden] - public static Kilogram operator *(Kilogram kg, double d) - { - return new Kilogram(kg.Val * d); - } - - [DebuggerHidden] - public static Kilogram operator *(double d, Kilogram kg) - { - return new Kilogram(d * kg.Val); - } - - public static Liter operator /(Kilogram kilogram, KilogramPerCubicMeter kilogramPerCubicMeter) - { - return SIBase<Liter>.Create(kilogram.Value() / kilogramPerCubicMeter.Value() * 1000); - } - } - - public class Liter : SIBase<Liter> - { - private static readonly int[] Units = { 0, 3, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Liter(double val) : base(val * 0.001, Units) { } - - public static Kilogram operator *(Liter liter, KilogramPerCubicMeter kilogramPerCubicMeter) - { - return SIBase<Kilogram>.Create(liter.Val / 1000 * kilogramPerCubicMeter.Value()); - } - } - - /// <summary> - /// - /// </summary> - public class NormLiter : SIBase<NormLiter> - { - private static readonly int[] Units = { 0, 3, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private NormLiter(double val) : base(val * 0.001, Units) { } - - public static NormLiterPerSecond operator /(NormLiter nl, Second s) - { - return SIBase<NormLiterPerSecond>.Create(nl.Val / s.Value()); - } - } - - /// <summary> - /// - /// </summary> - public class NormLiterPerSecond : SIBase<NormLiterPerSecond> - { - private static readonly int[] Units = { 0, 3, -1, 0, 0, 0, 0 }; - - [DebuggerHidden] - private NormLiterPerSecond(double val) : base(val * 0.001, Units) { } - - public static NormLiter operator *(NormLiterPerSecond nips, Second s) - { - return SIBase<NormLiter>.Create(nips.Val * s.Value()); - } - - public static NormLiterPerSecond operator *(NormLiterPerSecond nps, double val) - { - return Create(nps.Val * val); - } - } - - /// <summary> - /// SI Class for Kilogram per Second [kg]. - /// </summary> - public class KilogramPerSecond : SIBase<KilogramPerSecond> - { - private static readonly int[] Units = { 1, 0, -1, 0, 0, 0, 0 }; - - [DebuggerHidden] - private KilogramPerSecond(double value) : base(value, Units) { } - - [DebuggerHidden] - public static Kilogram operator *(KilogramPerSecond kilogramPerSecond, Second second) - { - return SIBase<Kilogram>.Create(kilogramPerSecond.Val * second.Value()); - } - } - - /// <summary> - /// SI Class for Square meter [m^2]. - /// </summary> - public class SquareMeter : SIBase<SquareMeter> - { - private static readonly int[] Units = { 0, 2, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private SquareMeter(double value) : base(value, Units) { } - } - - /// <summary> - /// SI Class for cubic meter [m^3]. - /// </summary> - public class CubicMeter : SIBase<CubicMeter> - { - private static readonly int[] Units = { 0, 3, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private CubicMeter(double value) - : base(value, Units) { } - } - - /// <summary> - /// SI Class for Kilogram Square Meter [kgm^2]. - /// </summary> - public class KilogramSquareMeter : SIBase<KilogramSquareMeter> - { - private static readonly int[] Units = { 1, 2, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private KilogramSquareMeter(double value) : base(value, Units) { } - - [DebuggerHidden] - public static NewtonMeter operator *(KilogramSquareMeter kilogramSquareMeter, PerSquareSecond perSquareSecond) - { - return SIBase<NewtonMeter>.Create(kilogramSquareMeter.Val * perSquareSecond.Value()); - } - } - - /// <summary> - /// SI Class for Kilogram Square Meter [kgm^2]. - /// </summary> - public class KilogramPerCubicMeter : SIBase<KilogramPerCubicMeter> - { - private static readonly int[] Units = { 1, -3, 0, 0, 0, 0, 0 }; - - [DebuggerHidden] - private KilogramPerCubicMeter(double value) : base(value, Units) { } - - [DebuggerHidden] - public static Kilogram operator *(KilogramPerCubicMeter kilogramPerCubicMeter, CubicMeter cubicMeter) - { - return SIBase<Kilogram>.Create(kilogramPerCubicMeter.Val * cubicMeter.Value()); - } - - public static Kilogram operator *(KilogramPerCubicMeter kilogramPerCubicMeter, Liter liter) - { - return SIBase<Kilogram>.Create(kilogramPerCubicMeter.Val * liter.Value() / 1000); - } - - //public static CubicMeter operator /(Kilogram kg, KilogramPerCubicMeter kgm3) - //{ - // return SIBase<CubicMeter>.Create(kg.Value() / kgm3.Val); - //} - } - - /// <summary> - /// SI Class for Kilogramm per watt second [kg/Ws]. - /// W = kgm^2/s^3 - /// </summary> - public class KilogramPerWattSecond : SIBase<KilogramPerWattSecond> - { - private static readonly int[] Units = { 0, -2, 2, 0, 0, 0, 0 }; - - [DebuggerHidden] - private KilogramPerWattSecond(double val) : base(val, Units) { } - } - - /// <summary> - /// SI Class for watt second [Ws]. - /// W = kgm^2/s^3 - /// </summary> - public class WattSecond : SIBase<WattSecond> - { - private static readonly int[] Units = { 1, 2, -2, 0, 0, 0, 0 }; - - [DebuggerHidden] - private WattSecond(double val) : base(val, Units) { } - - [DebuggerHidden] - public static Watt operator /(WattSecond wattSecond, Second second) - { - return SIBase<Watt>.Create(wattSecond.Val / second.Value()); - } - } - - /// <summary> - /// SI Class for Watt [W]. - /// </summary> - public class Watt : SIBase<Watt> - { - private static readonly int[] Units = { 1, 2, -3, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Watt(double val) : base(val, Units) { } - - /// <summary> - /// Implements the operator /. - /// </summary> - /// <param name="watt">The watt.</param> - /// <param name="newtonMeter">The newton meter.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static PerSecond operator /(Watt watt, NewtonMeter newtonMeter) - { - return SIBase<PerSecond>.Create(watt.Val / newtonMeter.Value()); - } - - [DebuggerHidden] - public static Newton operator /(Watt watt, MeterPerSecond meterPerSecond) - { - return SIBase<Newton>.Create(watt.Val / meterPerSecond.Value()); - } - - /// <summary> - /// Implements the operator /. - /// </summary> - /// <param name="watt">The watt.</param> - /// <param name="perSecond">The per second.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static NewtonMeter operator /(Watt watt, PerSecond perSecond) - { - return SIBase<NewtonMeter>.Create(watt.Val / perSecond.Value()); - } - - [DebuggerHidden] - public static WattSecond operator *(Watt watt, Second second) - { - return SIBase<WattSecond>.Create(watt.Val * second.Value()); - } - - [DebuggerHidden] - public static Watt operator *(Watt watt, double val) - { - return Create(watt.Val * val); - } - } - - /// <summary> - /// SI Class for Joule [J]. - /// J = Ws = kgm^2/s^2 - /// </summary> - public class Joule : SIBase<Joule> - { - private static readonly int[] Units = { 1, 2, -2, 0, 0, 0, 0 }; - - [DebuggerHidden] - private Joule(double val) : base(val, Units) { } - - public static implicit operator Joule(WattSecond self) - { - return Create(self.Value()); - } - - public static Joule operator +(Joule joule, WattSecond ws) - { - return Create(joule.Val + ws.Value()); - } - - public static Watt operator /(Joule joule, Second s) - { - return SIBase<Watt>.Create(joule.Val / s.Value()); - } - - public static JoulePerMeter operator /(Joule joule, Meter meter) - { - return SIBase<JoulePerMeter>.Create(joule.Val / meter.Value()); - } - } - - /// <summary> - /// SI Class for Watt [W]. - /// J = Ws - /// W = kgm^2/s^3 - /// </summary> - public class JoulePerKilogramm : SIBase<JoulePerKilogramm> - { - private static readonly int[] Units = { 0, 2, -2, 0, 0, 0, 0 }; - - private JoulePerKilogramm(double val) : base(val, Units) { } - - public static Joule operator *(Kilogram kg, JoulePerKilogramm jpg) - { - return SIBase<Joule>.Create(kg.Value() * jpg.Val); - } - } - - /// <summary> - /// SI Class for Joule per Meter [J/m]. - /// J = Ws - /// W = kgm^2/s^3 - /// </summary> - public class JoulePerMeter : SIBase<JoulePerMeter> - { - private static readonly int[] Units = { 1, 1, -2, 0, 0, 0, 0 }; - - [DebuggerHidden] - private JoulePerMeter(double val) : base(val, Units) { } - } - - /// <summary> - /// SI Class for one per second [1/s]. - /// </summary> - [DebuggerDisplay("rad/s: {Val} | rpm: {AsRPM}")] - public class PerSecond : SIBase<PerSecond> - { - private static readonly int[] Units = { 0, 0, -1, 0, 0, 0, 0 }; - - [DebuggerHidden] - private PerSecond(double val) : base(val, Units) { } - - [DebuggerHidden] - public static PerSquareSecond operator /(PerSecond perSecond, Second second) - { - return SIBase<PerSquareSecond>.Create(perSecond.Val / second.Value()); - } - - public double AsRPM - { - get { return Val * 60 / (2 * Math.PI); } - } - } - - /// <summary> - /// SI Class for Meter per second [m/s]. - /// </summary> - [DebuggerDisplay("{Val} | {AsKmph}")] - public class MeterPerSecond : SIBase<MeterPerSecond> - { - private static readonly int[] Units = { 0, 1, -1, 0, 0, 0, 0 }; - - [DebuggerHidden] - private MeterPerSecond(double val) : base(val, Units) { } - - public double AsKmph - { - get { return Val * 3.6; } - } - - /// <summary> - /// Implements the operator /. - /// </summary> - [DebuggerHidden] - public static PerSecond operator /(MeterPerSecond meterPerSecond, Meter meter) - { - return SIBase<PerSecond>.Create(meterPerSecond.Val / meter.Value()); - } - - /// <summary> - /// Implements the operator /. - /// </summary> - [DebuggerHidden] - public static Second operator /(MeterPerSecond meterPerSecond, MeterPerSquareSecond meterPerSquareSecond) - { - return SIBase<Second>.Create(meterPerSecond.Val / meterPerSquareSecond.Value()); - } - - /// <summary> - /// Implements the operator /. - /// </summary> - [DebuggerHidden] - public static MeterPerSquareSecond operator /(MeterPerSecond meterPerSecond, Second second) - { - return SIBase<MeterPerSquareSecond>.Create(meterPerSecond.Val / second.Value()); - } - - /// <summary> - /// Implements the operator *. - /// </summary> - [DebuggerHidden] - public static Meter operator *(MeterPerSecond meterPerSecond, Second second) - { - return SIBase<Meter>.Create(meterPerSecond.Val * second.Value()); - } - - /// <summary> - /// Implements the operator *. - /// </summary> - [DebuggerHidden] - public static MeterPerSquareSecond operator *(MeterPerSecond meterPerSecond, PerSecond perSecond) - { - return SIBase<MeterPerSquareSecond>.Create(meterPerSecond.Val * perSecond.Value()); - } - - /// <summary> - /// Implements the operator *. - /// </summary> - [DebuggerHidden] - public static Meter operator *(Second second, MeterPerSecond meterPerSecond) - { - return SIBase<Meter>.Create(second.Value() * meterPerSecond.Val); - } - } - - /// <summary> - /// SI Class for NewtonMeter [Nm]. - /// N = kgm/s^2 - /// </summary> - public class NewtonMeter : SIBase<NewtonMeter> - { - private static readonly int[] Units = { 1, 2, -2, 0, 0, 0, 0 }; - - [DebuggerHidden] - private NewtonMeter(double val) : base(val, Units) { } - - [DebuggerHidden] - public static Watt operator *(NewtonMeter newtonMeter, PerSecond perSecond) - { - return SIBase<Watt>.Create(newtonMeter.Val * perSecond.Value()); - } - - [DebuggerHidden] - public static Watt operator *(PerSecond perSecond, NewtonMeter newtonMeter) - { - return SIBase<Watt>.Create(perSecond.Value() * newtonMeter.Val); - } - - [DebuggerHidden] - public static Second operator /(NewtonMeter newtonMeter, Watt watt) - { - return SIBase<Second>.Create(newtonMeter.Val / watt.Value()); - } - - [DebuggerHidden] - public static PerSquareSecond operator /(NewtonMeter newtonMeter, KilogramSquareMeter kgKilogramSquareMeter) - { - return SIBase<PerSquareSecond>.Create(newtonMeter.Val / kgKilogramSquareMeter.Value()); - } - - [DebuggerHidden] - public static PerSecond operator /(NewtonMeter newtonMeter, NewtonMeterSecond newtonMeterSecond) - { - return SIBase<PerSecond>.Create(newtonMeter.Val / newtonMeterSecond.Value()); - } - - [DebuggerHidden] - public static Newton operator /(NewtonMeter newtonMeter, Meter meter) - { - return SIBase<Newton>.Create(newtonMeter.Val / meter.Value()); - } - - [DebuggerHidden] - public static NewtonMeterSecond operator /(NewtonMeter newtonMeter, PerSecond perSecond) - { - return SIBase<NewtonMeterSecond>.Create(newtonMeter.Val / perSecond.Value()); - } - } - - /// <summary> - /// SI Class for NewtonMeterSecond [Nms]. - /// N = kgm/s^2 - /// </summary> - public class NewtonMeterSecond : SIBase<NewtonMeterSecond> - { - private static readonly int[] Units = { 1, 2, -1, 0, 0, 0, 0 }; - private NewtonMeterSecond(double val) : base(val, Units) { } - } - - /// <summary> - /// SI Class for Amperer [A]. - /// </summary> - public class Ampere : SIBase<Ampere> - { - private static readonly int[] Units = { 0, 0, 0, 1, 0, 0, 0 }; - private Ampere(double val) : base(val, Units) { } - - public static Watt operator *(Ampere ampere, Volt volt) - { - return SIBase<Watt>.Create(volt.Value() * ampere.Val); - } - - public static Ampere operator *(Ampere ampere, double val) - { - return Create(ampere.Val * val); - } - - public static Volt operator /(Watt watt, Ampere ampere) - { - return SIBase<Volt>.Create(watt.Value() / ampere.Value()); - } - } - - /// <summary> - /// SI Class for Amperer [V]. - /// V = kgm^2/As^2 - /// </summary> - public class Volt : SIBase<Volt> - { - private static readonly int[] Units = { 1, 2, -2, -1, 0, 0, 0 }; - private Volt(double val) : base(val, Units) { } - - public static Watt operator *(Volt volt, Ampere ampere) - { - return SIBase<Watt>.Create(volt.Val * ampere.Value()); - } - - public static Ampere operator /(Watt watt, Volt volt) - { - return SIBase<Ampere>.Create(watt.Value() / volt.Value()); - } - } - - /// <summary> - /// Base Class for all special SI Classes. Not intended to be used directly. - /// Implements templated operators for type safety and convenience. - /// </summary> - /// <typeparam name="T"></typeparam> - public abstract class SIBase<T> : SI where T : SIBase<T> - { - private static readonly T ZeroPrototype; - - static SIBase() - { - const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance; - var constructorInfo = typeof(T).GetConstructor(bindingFlags, null, new[] { typeof(double) }, null); - var parameter = Expression.Parameter(typeof(double)); - var lambda = Expression.Lambda<Func<double, T>>(Expression.New(constructorInfo, parameter), parameter); - Constructor = lambda.Compile(); - ZeroPrototype = Constructor(0); - } - - /// <summary> - /// The constructor for the generic type T. - /// </summary> - private static readonly Func<double, T> Constructor; - - /// <summary> - /// Creates the specified special SI object. - /// </summary> - /// <param name="val">The value of the SI object.</param> - [DebuggerStepThrough] - public static T Create(double val) - { - if (val == 0) - { - return ZeroPrototype; - } - - return Constructor(val); - } - - [DebuggerStepThrough] - protected SIBase(double value, int[] units) : base(value, units, 0) { } - - [DebuggerStepThrough] - public new T Abs() - { - return Create(Math.Abs(Val)); - } - - #region Operators - - /// <summary> - /// Implements the operator + for two specialized SI Classes. - /// </summary> - /// <param name="si1">The si1.</param> - /// <param name="si2">The si2.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator +(SIBase<T> si1, SIBase<T> si2) - { - return Create(si1.Val + si2.Val); - } - - /// <summary> - /// Implements the operator + for a specialized SI Class and a generic SI Class. - /// </summary> - /// <param name="si1">The si1.</param> - /// <param name="si2">The si2.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator +(SIBase<T> si1, SI si2) - { - return ((si1 as SI) + si2).Cast<T>(); - } - - /// <summary> - /// Implements the operator + for a generic SI Class and a specialized SI Class. - /// </summary> - /// <param name="si1">The si1.</param> - /// <param name="si2">The si2.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator +(SI si1, SIBase<T> si2) - { - return (si1 + (si2 as SI)).Cast<T>(); - } - - /// <summary> - /// Implements the unary operator -. - /// </summary> - /// <param name="si1">The si1.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator -(SIBase<T> si1) - { - return Create(-si1.Val); - } - - /// <summary> - /// Implements the operator - for two specialized SI classes. - /// </summary> - /// <param name="si1">The si1.</param> - /// <param name="si2">The si2.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator -(SIBase<T> si1, SIBase<T> si2) - { - return Create(si1.Val - si2.Val); - } - - /// <summary> - /// Implements the operator - for a specialized SI class and a generic SI class. - /// </summary> - /// <param name="si1">The si1.</param> - /// <param name="si2">The si2.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator -(SIBase<T> si1, SI si2) - { - return ((si1 as SI) - si2).Cast<T>(); - } - - /// <summary> - /// Implements the operator - for a generic SI class and a specialized SI class. - /// </summary> - /// <param name="si1">The si1.</param> - /// <param name="si2">The si2.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator -(SI si1, SIBase<T> si2) - { - return (si1 - (si2 as SI)).Cast<T>(); - } - - /// <summary> - /// Implements the operator * for a double and a specialized SI class. - /// </summary> - /// <param name="d">The double value.</param> - /// <param name="si">The si.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator *(double d, SIBase<T> si) - { - return Create(d * si.Val); - } - - /// <summary> - /// Implements the operator * for a specialized SI class and a double. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="d">The double.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator *(SIBase<T> si, double d) - { - return Create(si.Val * d); - } - - /// <summary> - /// Implements the operator / for a specialized SI class and a double. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="d">The double.</param> - /// <returns> - /// The result of the operator. - /// </returns> - [DebuggerHidden] - public static T operator /(SIBase<T> si, double d) - { - return Create(si.Val / d); - } - - [DebuggerHidden] - public static Scalar operator /(SIBase<T> si, SIBase<T> si2) - { - return SIBase<Scalar>.Create(si.Val / si2.Val); - } - - #endregion - } - - /// <summary> - /// Class for representing generic SI Units. - /// </summary> - /// <remarks> - /// Usage: new SI(1.0).Newton.Meter, new SI(2.3).Rounds.Per.Minute - /// </remarks> - [DebuggerDisplay("{Val}")] - public class SI : IComparable - { - /// <summary> - /// The basic scalar value of the SI. - /// </summary> - protected readonly double Val; - - /// <summary> - /// The array of the SI units. - /// </summary> - private readonly int[] _units; - - // TODO mk-2017-09-14: can the mass be solved differently? - private UnitInstance.IsMass _isMass; - - /// <summary> - /// Initializes a new instance of the <see cref="SI"/> class which allows to construct a new SI with all parameters. - /// </summary> - /// <param name="val">The value.</param> - /// <param name="units">The units.</param> - /// <param name="isMassParam"></param> - protected SI(double val, int[] units, UnitInstance.IsMass isMassParam) - { - Val = val; - _isMass = isMassParam; - _units = units; - - if (double.IsNaN(Val)) - { - throw new VectoException("NaN [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); - } - - if (double.IsInfinity(Val)) - { - throw new VectoException("Infinity [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); - } - } - - public SI(UnitInstance si, double val = 0) : this(val * si.Factor, si.GetSIUnits(), si.GetGrammMode()) - { - - } - - /// <summary> - /// Initializes a new instance of the <see cref="SI"/> class which copies the units from an already existing SI. - /// </summary> - /// <param name="val">The value.</param> - /// <param name="unit">The unit.</param> - [DebuggerHidden] - private SI(double val, SI unit) : this(val, unit._units, unit._isMass) { } - - [DebuggerHidden] - private SI(SI si, double factor, int[] unitsParam, UnitInstance.IsMass isMassParam) - { - Val = si.Val / factor; - _isMass = isMassParam; - _units = unitsParam; - - if (double.IsNaN(Val)) - { - throw new VectoException("NaN [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); - } - - if (double.IsInfinity(Val)) - { - throw new VectoException("Infinity [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); - } - } - - public SI ConvertTo(UnitInstance si) - { - - if (!SIUtils.CompareUnits(_units, si.GetSIUnits())) - { - throw new VectoException( - "Unit missing. Conversion not possible. [{0}] does not contain a [{1}].", - GetUnitString(_units), si.GetSIUnits()); - } - - var factorValue = si.Factor; - - - if ((_isMass & UnitInstance.IsMass.IsGramm) == UnitInstance.IsMass.IsGramm) - { - factorValue *= 1000; - } - - if ((si.GetGrammMode() & UnitInstance.IsMass.IsGramm) == UnitInstance.IsMass.IsGramm) - { - factorValue /= 1000; - _isMass |= UnitInstance.IsMass.IsGramm; - } - - - return new SI(this, unitsParam: si.GetSIUnits(), factor: factorValue, - isMassParam: _isMass); - } - - /// <summary> - /// Casts the SI Unit to the concrete unit type (if the units allow such an cast). - /// </summary> - /// <typeparam name="T">the specialized SI unit. e.g. Watt, NewtonMeter, Second</typeparam> - [DebuggerHidden] - public T Cast<T>() where T : SIBase<T> - { - var si = ToBasicUnits(); - var t = SIBase<T>.Create(si.Val); - if (!si.HasEqualUnit(t)) - { - throw new VectoException("SI Unit Conversion failed: From {0} to {1}", si, t); - } - return t; - } - - /// <summary> - /// Converts the derived SI units to the basic units and returns this as a new SI object. - /// </summary> - public SI ToBasicUnits() - { - return new SI(Val, _units, _isMass); - } - - - /// <summary> - /// Gets the underlying scalar double value. - /// </summary> - [DebuggerHidden] - public double Value() - { - return Val; - } - - /// <summary> - /// Clones this instance. - /// </summary> - public SI Clone() - { - return new SI(Val, _units, _isMass); - } - - /// <summary> - /// Returns the absolute value. - /// </summary> - public SI Abs() - { - return new SI(Math.Abs(Val), this); - } - - /// <summary> - /// Returns the numerical sign of the SI. - /// </summary> - /// <returns>-1 if si < 0. 0 if si==0, 1 if si > 0.</returns> - [DebuggerHidden] - public int Sign() - { - return Math.Sign(Val); - } - - // TODO mk 2017-09-14: can this method be removed? - private static double GtoKg(SI si) - { - var result = 1.0; - - if ((si._isMass & UnitInstance.IsMass.IsGramm) == UnitInstance.IsMass.IsGramm) - { - result = 0.001; - } - - return result; - } - - #region Operators - - [DebuggerHidden] - public static SI operator +(SI si1, SI si2) - { - if (!si1.HasEqualUnit(si2)) - { - throw new VectoException("Operator '+' can only operate on SI Objects with the same unit. Got: {0} + {1}", si1, si2); - } - - - return new SI(si1.Val * GtoKg(si1) + si2.Val * GtoKg(si2), si1); - } - - [DebuggerHidden] - public static SI operator -(SI si1, SI si2) - { - if (!si1.HasEqualUnit(si2)) - { - throw new VectoException("Operator '-' can only operate on SI Objects with the same unit. Got: {0} - {1}", si1, si2); - } - return new SI(si1.Val * GtoKg(si1) - si2.Val * GtoKg(si2), si1); - } - - [DebuggerHidden] - public static SI operator -(SI si1) - { - return new SI(-si1.Val * GtoKg(si1), si1); - } - - public static SI operator *(SI si1, SI si2) - { - var unitArray = SIUtils.CombineUnits(si1._units, si2._units); - return new SI(si1.Val * GtoKg(si1) * (si2.Val * GtoKg(si2)), unitArray, UnitInstance.IsMass.IsKiloGramm); - } - - [DebuggerHidden] - public static SI operator *(SI si1, double d) - { - return new SI(si1.Val * GtoKg(si1) * d, si1); - } - - [DebuggerHidden] - public static SI operator *(double d, SI si1) - { - return new SI(d * si1.Val * GtoKg(si1), si1); - } - - public static SI operator /(SI si1, SI si2) - { - double result; - try - { - result = si1.Val * GtoKg(si1) / (si2.Val * GtoKg(si2)); - - // bad cases: Infinity = x / 0.0 (for x != 0), NaN = 0.0 / 0.0 - if (double.IsInfinity(result) || double.IsNaN(result)) - { - throw new DivideByZeroException(); - } - } - catch (DivideByZeroException ex) - { - throw new VectoException( - string.Format("Can not compute division by zero ([{0}] / 0[{1}])", si1.GetUnitString(), si2.GetUnitString()), ex); - } - - var unitArray = SIUtils.CombineUnits(si1._units, SIUtils.MultiplyUnits(si2._units, -1)); - - return new SI(result, unitArray, UnitInstance.IsMass.IsKiloGramm); - } - - [DebuggerHidden] - public static SI operator /(SI si1, double d) - { - if (d.IsEqual(0)) - { - throw new VectoException(string.Format("Can not compute division by zero ([{0}] / 0)", si1.GetUnitString()), new DivideByZeroException()); - } - - return new SI(si1.Val * GtoKg(si1) / d, si1); - } - - [DebuggerHidden] - public static SI operator /(double d, SI si1) - { - if (si1.IsEqual(0)) - { - throw new VectoException(string.Format("Can not compute division by zero (x / 0[{0}])", si1.GetUnitString()), - new DivideByZeroException()); - } - - return new SI(d / (si1.Val * GtoKg(si1)), si1._units.Select(u => -u).ToArray(), si1._isMass); - } - - [DebuggerHidden] - public static bool operator <(SI si1, SI si2) - { - if (!si1.HasEqualUnit(si2)) - { - throw new VectoException("Operator '<' can only operate on SI Objects with the same unit. Got: {0} < {1}", si1, si2); - } - return si1.Val * GtoKg(si1) < si2.Val * GtoKg(si2); - } - - [DebuggerHidden] - public static bool operator <(SI si1, double d) - { - return si1 != null && si1.Val * GtoKg(si1) < d; - } - - [DebuggerHidden] - public static bool operator >(SI si1, SI si2) - { - if (!si1.HasEqualUnit(si2)) - { - throw new VectoException("Operator '>' can only operate on SI Objects with the same unit. Got: {0} > {1}", si1, si2); - } - return si1.Val * GtoKg(si1) > si2.Val * GtoKg(si2); - } - - [DebuggerHidden] - public static bool operator >(SI si1, double d) - { - return si1 != null && si1.Val * GtoKg(si1) > d; - } - - [DebuggerHidden] - public static bool operator >(double d, SI si1) - { - return si1 != null && d > si1.Val * GtoKg(si1); - } - - [DebuggerHidden] - public static bool operator <(double d, SI si1) - { - return si1 != null && d < si1.Val * GtoKg(si1); - } - - [DebuggerHidden] - public static bool operator <=(SI si1, SI si2) - { - if (!si1.HasEqualUnit(si2)) - { - throw new VectoException("Operator '<=' can only operate on SI Objects with the same unit. Got: {0} <= {1}", si1, - si2); - } - return si1.Val * GtoKg(si1) <= si2.Val * GtoKg(si2); - } - - [DebuggerHidden] - public static bool operator <=(SI si1, double d) - { - return si1 != null && si1.Val * GtoKg(si1) <= d; - } - - [DebuggerHidden] - public static bool operator >=(SI si1, SI si2) - { - if (!si1.HasEqualUnit(si2)) - { - throw new VectoException("Operator '>=' can only operate on SI Objects with the same unit. Got: {0} >= {1}", si1, - si2); - } - return si1.Val * GtoKg(si1) >= si2.Val * GtoKg(si2); - } - - [DebuggerHidden] - public static bool operator >=(SI si1, double d) - { - return si1 != null && si1.Val * GtoKg(si1) >= d; - } - - [DebuggerHidden] - public static bool operator >=(double d, SI si1) - { - return si1 != null && d >= si1.Val * GtoKg(si1); - } - - [DebuggerHidden] - public static bool operator <=(double d, SI si1) - { - return si1 != null && d <= si1.Val * GtoKg(si1); - } - - /// <summary> - /// Determines whether the SI is between lower and uppper bound. - /// </summary> - /// <param name="lower">The lower bound.</param> - /// <param name="upper">The upper bound.</param> - /// <returns></returns> - public bool IsBetween(SI lower, SI upper) - { - return lower <= Val * GtoKg(this) && Val * GtoKg(this) <= upper; - } - - /// <summary> - /// Determines whether the SI is between lower and upper bound. - /// </summary> - /// <param name="lower">The lower bound.</param> - /// <param name="upper">The upper bound.</param> - /// <returns></returns> - public bool IsBetween(double lower, double upper) - { - return lower <= Val * GtoKg(this) && Val * GtoKg(this) <= upper; - } - - #endregion - - #region ToString - - /// <summary> - /// Returns the Unit Part of the SI Unit Expression. - /// </summary> - public string GetUnitString(int[] units = null) - { - if (units == null) - { - units = _units; - } - return Unit.GetUnitString(units, (_isMass & UnitInstance.IsMass.IsGramm) == UnitInstance.IsMass.IsGramm); - } - - public override string ToString() - { - return ToString(null); - } - - private string ToString(string format) - { - if (string.IsNullOrEmpty(format)) - { - format = "F4"; - } - - return string.Format(CultureInfo.InvariantCulture, "{0:" + format + "} [{2}]", Val, format, GetUnitString()); - } - - #endregion - - #region Equality members - - /// <summary> - /// Compares the Unit-Parts of two SI Units. - /// </summary> - /// <param name="si">The si.</param> - /// <returns></returns> - [DebuggerHidden] - public bool HasEqualUnit(SI si) - { - return SIUtils.CompareUnits(_units, si._units); - } - - /// <summary> - /// Determines whether the specified <see cref="System.Object" />, is equal to this instance. - /// </summary> - /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param> - /// <returns> - /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>. - /// </returns> - public override bool Equals(object obj) - { - if (ReferenceEquals(null, obj)) - { - return false; - } - if (ReferenceEquals(this, obj)) - { - return true; - } - var other = obj as SI; - - var valFac = Val * GtoKg(this); - return other != null && valFac.Equals(other.Val * GtoKg(other)) && HasEqualUnit(other); - } - - /// <summary> - /// Determines whether the specified si is equal. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - public bool IsEqual(SI si, SI tolerance = null) - { - var valFac = Val * GtoKg(this); - return (tolerance == null || HasEqualUnit(tolerance)) && HasEqualUnit(si) && valFac.IsEqual(si.Val * GtoKg(si), tolerance == null ? DoubleExtensionMethods.Tolerance : (tolerance.Value() * GtoKg(tolerance))); - } - - /// <summary> - /// Determines whether the specified value is equal. - /// </summary> - /// <param name="val">The value.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - [DebuggerHidden] - public bool IsEqual(double val, double tolerance = DoubleExtensionMethods.Tolerance) - { - var valFac = Val * GtoKg(this); - return valFac.IsEqual(val, tolerance); - } - - /// <summary> - /// Determines whether the specified si is smaller. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - public bool IsSmaller(SI si, SI tolerance = null) - { - if (!HasEqualUnit(si)) - { - throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); - } - if (tolerance != null && !HasEqualUnit(tolerance)) - { - throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); - } - - var valFac = Val * GtoKg(this); - return valFac.IsSmaller(si.Val * GtoKg(si), tolerance == null ? DoubleExtensionMethods.Tolerance : (tolerance.Value() * GtoKg(tolerance))); - } - - /// <summary> - /// Determines whether the specified si is smaller. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - public bool IsSmaller(SI si, double tolerance) - { - if (!HasEqualUnit(si)) - { - throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); - } - - var valFac = Val * GtoKg(this); - return valFac.IsSmaller(si.Val * GtoKg(si), tolerance); - } - - /// <summary> - /// Determines whether [is smaller or equal] [the specified si]. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - public bool IsSmallerOrEqual(SI si, SI tolerance = null) - { - if (!HasEqualUnit(si)) - { - throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); - } - if (tolerance != null && !HasEqualUnit(tolerance)) - { - throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); - } - - var valFac = Val * GtoKg(this); - - return valFac.IsSmallerOrEqual(si.Val * GtoKg(si), tolerance == null ? DoubleExtensionMethods.Tolerance : (tolerance.Value() * GtoKg(tolerance))); - } - - /// <summary> - /// Determines whether the specified si is greater. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - public bool IsGreater(SI si, SI tolerance = null) - { - if (!HasEqualUnit(si)) - { - throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); - } - if (tolerance != null && !HasEqualUnit(tolerance)) - { - throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); - } - - var valFac = Val * GtoKg(this); - return valFac.IsGreater(si.Val * GtoKg(si), tolerance == null ? DoubleExtensionMethods.Tolerance : (tolerance.Value() * GtoKg(tolerance))); - } - - /// <summary> - /// Determines whether the specified si is greater. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - [DebuggerStepThrough] - public bool IsGreater(SI si, double tolerance) - { - if (!HasEqualUnit(si)) - { - throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); - } - - var valFac = Val * GtoKg(this); - - return valFac.IsGreater(si.Val * GtoKg(si), tolerance); - } - - /// <summary> - /// Determines whether [is greater or equal] [the specified si]. - /// </summary> - /// <param name="si">The si.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - [DebuggerStepThrough] - public bool IsGreaterOrEqual(SI si, SI tolerance = null) - { - if (!HasEqualUnit(si)) - { - throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); - } - if (tolerance != null && !HasEqualUnit(tolerance)) - { - throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); - } - - var valFac = Val * GtoKg(this); - return valFac.IsGreaterOrEqual(si.Val * GtoKg(si), tolerance == null ? DoubleExtensionMethods.Tolerance : (tolerance.Value() * GtoKg(tolerance))); - } - - /// <summary> - /// Determines whether the specified value is smaller. - /// </summary> - /// <param name="val">The value.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - [DebuggerStepThrough] - public bool IsSmaller(double val, double tolerance = DoubleExtensionMethods.Tolerance) - { - return Val.IsSmaller(val, tolerance); - } - - /// <summary> - /// Determines whether [is smaller or equal] [the specified value]. - /// </summary> - /// <param name="val">The value.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - [DebuggerStepThrough] - public bool IsSmallerOrEqual(double val, double tolerance = DoubleExtensionMethods.Tolerance) - { - return Val.IsSmallerOrEqual(val, tolerance); - } - - /// <summary> - /// Determines whether the specified value is greater. - /// </summary> - /// <param name="val">The value.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - [DebuggerStepThrough] - public bool IsGreater(double val, double tolerance = DoubleExtensionMethods.Tolerance) - { - return Val.IsGreater(val, tolerance); - } - - /// <summary> - /// Determines whether [is greater or equal] [the specified value]. - /// </summary> - /// <param name="val">The value.</param> - /// <param name="tolerance">The tolerance.</param> - /// <returns></returns> - [DebuggerStepThrough] - public bool IsGreaterOrEqual(double val, double tolerance = DoubleExtensionMethods.Tolerance) - { - return Val.IsGreaterOrEqual(val, tolerance); - } - - public override int GetHashCode() - { - unchecked - { - // ReSharper disable once NonReadonlyMemberInGetHashCode - var hashCode = Val.GetHashCode(); - hashCode = (hashCode * 397) ^ (_units != null ? _units.GetHashCode() : 0); - return hashCode; - } - } - - public int CompareTo(object obj) - { - var si = obj as SI; - if (si == null) - { - return 1; - } - - if (!HasEqualUnit(si)) - { - //if (SIUtils.GetnumberofSIUnits(si.Units) >= SIUtils.GetnumberofSIUnits(Units)) - if (si._units.Sum<int>(n => Math.Abs(n)) >= _units.Sum<int>(n => Math.Abs(n))) - { - return -1; - } - return 1; - } - - if (this > si) - { - return 1; - } - return this < si ? -1 : 0; - } - - public static bool operator ==(SI left, SI right) - { - return Equals(left, right); - } - - public static bool operator !=(SI left, SI right) - { - return !Equals(left, right); - } - - #endregion - - /// <summary> - /// Convert the SI to a string in the wished output format. - /// </summary> - /// <param name="decimals">The decimals.</param> - /// <param name="outputFactor">The output factor.</param> - /// <param name="showUnit">The show unit.</param> - /// <returns></returns> - public string ToOutputFormat(uint? decimals = null, double? outputFactor = null, bool? showUnit = null) - { - decimals = decimals ?? 4; - outputFactor = outputFactor ?? 1.0; - showUnit = showUnit ?? false; - - if (showUnit.Value) - { - return (Val * outputFactor.Value).ToString("F" + decimals.Value, CultureInfo.InvariantCulture) + " [" + - GetUnitString() + "]"; - } - - return (Val * outputFactor.Value).ToString("F" + decimals.Value, CultureInfo.InvariantCulture); - } - - public string ToGUIFormat() - { - return Val.ToGUIFormat(); - } - - public string ToXMLFormat(uint? decimals = null) - { - decimals = decimals ?? 2; - return Val.ToString("F" + decimals.Value, CultureInfo.InvariantCulture); - } - - public class EqualityComparer<T> : IEqualityComparer<T> where T : SI - { - private readonly double _precision; - - public EqualityComparer(double precision = DoubleExtensionMethods.Tolerance) - { - _precision = precision; - } - - public bool Equals(T x, T y) - { - return x.IsEqual(y.Value(), _precision); - } - - public int GetHashCode(T obj) - { - return obj.Value().GetHashCode(); - } - } - } + /// <summary> + /// SI Class for Scalar Values. Converts implicitely to double and is only castable if the SI value has no units. + /// </summary> + public class Scalar : SIBase<Scalar> + { + private static readonly int[] Units = { 0, 0, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Scalar(double val) : base(val, Units) { } + + public static implicit operator double(Scalar self) + { + return self.Val; + } + + [DebuggerHidden] + public static Scalar operator +(Scalar si1, Scalar si2) + { + return Create(si1.Val + si2.Val); + } + + [DebuggerHidden] + public static Scalar operator +(Scalar si1, double si2) + { + return Create(si1.Val + si2); + } + + [DebuggerHidden] + public static Scalar operator +(double si1, Scalar si2) + { + return Create(si1 + si2.Val); + } + + [DebuggerHidden] + public static Scalar operator -(Scalar si1, Scalar si2) + { + return Create(si1.Val - si2.Val); + } + + [DebuggerHidden] + public static Scalar operator -(Scalar si1, double si2) + { + return Create(si1.Val - si2); + } + + [DebuggerHidden] + public static Scalar operator -(double si1, Scalar si2) + { + return Create(si1 - si2.Val); + } + } + + /// <summary> + /// SI Class for Newton [N]. + /// </summary> + public class Newton : SIBase<Newton> + { + private static readonly int[] Units = { 1, 1, -2, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Newton(double val) : base(val, Units) { } + + [DebuggerHidden] + public static NewtonMeter operator *(Newton newton, Meter meter) + { + return SIBase<NewtonMeter>.Create(newton.Val * meter.Value()); + } + + [DebuggerHidden] + public static Watt operator *(Newton newton, MeterPerSecond meterPerSecond) + { + return SIBase<Watt>.Create(newton.Val * meterPerSecond.Value()); + } + + [DebuggerHidden] + public static Watt operator *(MeterPerSecond meterPerSecond, Newton newton) + { + return SIBase<Watt>.Create(newton.Val * meterPerSecond.Value()); + } + } + + /// <summary> + /// SI Class for Radian [] (rad). + /// </summary> + public class Radian : SIBase<Radian> + { + private static readonly int[] Units = { 0, 0, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Radian(double val) : base(val, Units) { } + } + + /// <summary> + /// SI Class for PerSquareSecond [1/s^2]. + /// </summary> + public class PerSquareSecond : SIBase<PerSquareSecond> + { + private static readonly int[] Units = { 0, 0, -2, 0, 0, 0, 0 }; + [DebuggerHidden] + private PerSquareSecond(double val) : base(val, Units) { } + + [DebuggerHidden] + public static PerSecond operator *(PerSquareSecond perSquareSecond, Second second) + { + return SIBase<PerSecond>.Create(perSquareSecond.Val * second.Value()); + } + } + + /// <summary> + /// SI Class for Meter per square second [m/s^2]. + /// </summary> + public class MeterPerSquareSecond : SIBase<MeterPerSquareSecond> + { + private static readonly int[] Units = { 0, 1, -2, 0, 0, 0, 0 }; + + [DebuggerHidden] + private MeterPerSquareSecond(double val) : base(val, Units) { } + + /// <summary> + /// Implements the operator *. + /// </summary> + [DebuggerHidden] + public static MeterPerSecond operator *(MeterPerSquareSecond meterPerSecond, Second second) + { + return SIBase<MeterPerSecond>.Create(meterPerSecond.Val * second.Value()); + } + } + + /// <summary> + /// SI Class for Second [s]. + /// </summary> + public class Second : SIBase<Second> + { + private static readonly int[] Units = { 0, 0, 1, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Second(double val) : base(val, Units) { } + } + + /// <summary> + /// SI Class for Meter [m]. + /// </summary> + public class Meter : SIBase<Meter> + { + private static readonly int[] Units = { 0, 1, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Meter(double val) : base(val, Units) { } + + [DebuggerHidden] + public static MeterPerSecond operator /(Meter meter, Second second) + { + return SIBase<MeterPerSecond>.Create(meter.Val / second.Value()); + } + + [DebuggerHidden] + public static MeterPerSecond operator *(Meter meter, PerSecond perSecond) + { + return SIBase<MeterPerSecond>.Create(meter.Val * perSecond.Value()); + } + + /// <summary> + /// Implements the operator /. + /// </summary> + [DebuggerHidden] + public static Second operator /(Meter second, MeterPerSecond meterPerSecond) + { + return SIBase<Second>.Create(second.Val / meterPerSecond.Value()); + } + } + + /// <summary> + /// SI Class for KilogramPerMeter [kg/m]. + /// </summary> + public class KilogramPerMeter : SIBase<KilogramPerMeter> + { + private static readonly int[] Units = { 1, -1, 0, 0, 0, 0, 0 }; + [DebuggerHidden] + private KilogramPerMeter(double val) : base(val, Units) { } + } + + /// <summary> + /// SI Class for Liter per Second [l/s]. + /// </summary> + public class LiterPerSecond : SIBase<LiterPerSecond> + { + private static readonly int[] Units = { 0, 3, -1, 0, 0, 0, 0 }; + + private LiterPerSecond(double val) : base(val * 0.001, Units) { } + } + + /// <summary> + /// SI Class for Kilogram [kg]. + /// </summary> + public class Kilogram : SIBase<Kilogram> + { + private static readonly int[] Units = { 1, 0, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Kilogram(double val) : base(val, Units) { } + + [DebuggerHidden] + public static KilogramPerSecond operator /(Kilogram kg, Second second) + { + return SIBase<KilogramPerSecond>.Create(kg.Val / second.Value()); + } + + [DebuggerHidden] + public static SI operator /(Kilogram kg, Joule j) + { + return (kg as SI) / j; + } + + [DebuggerHidden] + public static Scalar operator /(Kilogram kg, Kilogram kg2) + { + return SIBase<Scalar>.Create(kg.Val / kg2.Val); + } + + [DebuggerHidden] + public static KilogramPerMeter operator /(Kilogram kg, Meter m) + { + return SIBase<KilogramPerMeter>.Create(kg.Val / m.Value()); + } + + [DebuggerHidden] + public static Newton operator *(Kilogram kg, MeterPerSquareSecond m) + { + return SIBase<Newton>.Create(kg.Val * m.Value()); + } + + [DebuggerHidden] + public static Kilogram operator *(Kilogram kg, double d) + { + return new Kilogram(kg.Val * d); + } + + [DebuggerHidden] + public static Kilogram operator *(double d, Kilogram kg) + { + return new Kilogram(d * kg.Val); + } + + public static Liter operator /(Kilogram kilogram, KilogramPerCubicMeter kilogramPerCubicMeter) + { + return SIBase<Liter>.Create(kilogram.Value() / kilogramPerCubicMeter.Value() * 1000); + } + } + + public class Liter : SIBase<Liter> + { + private static readonly int[] Units = { 0, 3, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Liter(double val) : base(val * 0.001, Units) { } + + public static Kilogram operator *(Liter liter, KilogramPerCubicMeter kilogramPerCubicMeter) + { + return SIBase<Kilogram>.Create(liter.Val / 1000 * kilogramPerCubicMeter.Value()); + } + } + + /// <summary> + /// + /// </summary> + public class NormLiter : SIBase<NormLiter> + { + private static readonly int[] Units = { 0, 3, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private NormLiter(double val) : base(val * 0.001, Units) { } + + public static NormLiterPerSecond operator /(NormLiter nl, Second s) + { + return SIBase<NormLiterPerSecond>.Create(nl.Val / s.Value()); + } + } + + /// <summary> + /// + /// </summary> + public class NormLiterPerSecond : SIBase<NormLiterPerSecond> + { + private static readonly int[] Units = { 0, 3, -1, 0, 0, 0, 0 }; + + [DebuggerHidden] + private NormLiterPerSecond(double val) : base(val * 0.001, Units) { } + + public static NormLiter operator *(NormLiterPerSecond nips, Second s) + { + return SIBase<NormLiter>.Create(nips.Val * s.Value()); + } + + public static NormLiterPerSecond operator *(NormLiterPerSecond nps, double val) + { + return Create(nps.Val * val); + } + } + + /// <summary> + /// SI Class for Kilogram per Second [kg]. + /// </summary> + public class KilogramPerSecond : SIBase<KilogramPerSecond> + { + private static readonly int[] Units = { 1, 0, -1, 0, 0, 0, 0 }; + + [DebuggerHidden] + private KilogramPerSecond(double value) : base(value, Units) { } + + [DebuggerHidden] + public static Kilogram operator *(KilogramPerSecond kilogramPerSecond, Second second) + { + return SIBase<Kilogram>.Create(kilogramPerSecond.Val * second.Value()); + } + } + + /// <summary> + /// SI Class for Square meter [m^2]. + /// </summary> + public class SquareMeter : SIBase<SquareMeter> + { + private static readonly int[] Units = { 0, 2, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private SquareMeter(double value) : base(value, Units) { } + } + + /// <summary> + /// SI Class for cubic meter [m^3]. + /// </summary> + public class CubicMeter : SIBase<CubicMeter> + { + private static readonly int[] Units = { 0, 3, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private CubicMeter(double value) + : base(value, Units) { } + } + + /// <summary> + /// SI Class for Kilogram Square Meter [kgm^2]. + /// </summary> + public class KilogramSquareMeter : SIBase<KilogramSquareMeter> + { + private static readonly int[] Units = { 1, 2, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private KilogramSquareMeter(double value) : base(value, Units) { } + + [DebuggerHidden] + public static NewtonMeter operator *(KilogramSquareMeter kilogramSquareMeter, PerSquareSecond perSquareSecond) + { + return SIBase<NewtonMeter>.Create(kilogramSquareMeter.Val * perSquareSecond.Value()); + } + } + + /// <summary> + /// SI Class for Kilogram Square Meter [kgm^2]. + /// </summary> + public class KilogramPerCubicMeter : SIBase<KilogramPerCubicMeter> + { + private static readonly int[] Units = { 1, -3, 0, 0, 0, 0, 0 }; + + [DebuggerHidden] + private KilogramPerCubicMeter(double value) : base(value, Units) { } + + [DebuggerHidden] + public static Kilogram operator *(KilogramPerCubicMeter kilogramPerCubicMeter, CubicMeter cubicMeter) + { + return SIBase<Kilogram>.Create(kilogramPerCubicMeter.Val * cubicMeter.Value()); + } + + public static Kilogram operator *(KilogramPerCubicMeter kilogramPerCubicMeter, Liter liter) + { + return SIBase<Kilogram>.Create(kilogramPerCubicMeter.Val * liter.Value() / 1000); + } + + //public static CubicMeter operator /(Kilogram kg, KilogramPerCubicMeter kgm3) + //{ + // return SIBase<CubicMeter>.Create(kg.Value() / kgm3.Val); + //} + } + + /// <summary> + /// SI Class for Kilogramm per watt second [kg/Ws]. + /// W = kgm^2/s^3 + /// </summary> + public class KilogramPerWattSecond : SIBase<KilogramPerWattSecond> + { + private static readonly int[] Units = { 0, -2, 2, 0, 0, 0, 0 }; + + [DebuggerHidden] + private KilogramPerWattSecond(double val) : base(val, Units) { } + } + + /// <summary> + /// SI Class for watt second [Ws]. + /// W = kgm^2/s^3 + /// </summary> + public class WattSecond : SIBase<WattSecond> + { + private static readonly int[] Units = { 1, 2, -2, 0, 0, 0, 0 }; + + [DebuggerHidden] + private WattSecond(double val) : base(val, Units) { } + + [DebuggerHidden] + public static Watt operator /(WattSecond wattSecond, Second second) + { + return SIBase<Watt>.Create(wattSecond.Val / second.Value()); + } + } + + /// <summary> + /// SI Class for Watt [W]. + /// </summary> + public class Watt : SIBase<Watt> + { + private static readonly int[] Units = { 1, 2, -3, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Watt(double val) : base(val, Units) { } + + /// <summary> + /// Implements the operator /. + /// </summary> + /// <param name="watt">The watt.</param> + /// <param name="newtonMeter">The newton meter.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static PerSecond operator /(Watt watt, NewtonMeter newtonMeter) + { + return SIBase<PerSecond>.Create(watt.Val / newtonMeter.Value()); + } + + [DebuggerHidden] + public static Newton operator /(Watt watt, MeterPerSecond meterPerSecond) + { + return SIBase<Newton>.Create(watt.Val / meterPerSecond.Value()); + } + + /// <summary> + /// Implements the operator /. + /// </summary> + /// <param name="watt">The watt.</param> + /// <param name="perSecond">The per second.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static NewtonMeter operator /(Watt watt, PerSecond perSecond) + { + return SIBase<NewtonMeter>.Create(watt.Val / perSecond.Value()); + } + + [DebuggerHidden] + public static WattSecond operator *(Watt watt, Second second) + { + return SIBase<WattSecond>.Create(watt.Val * second.Value()); + } + + [DebuggerHidden] + public static Watt operator *(Watt watt, double val) + { + return Create(watt.Val * val); + } + } + + /// <summary> + /// SI Class for Joule [J]. + /// J = Ws = kgm^2/s^2 + /// </summary> + public class Joule : SIBase<Joule> + { + private static readonly int[] Units = { 1, 2, -2, 0, 0, 0, 0 }; + + [DebuggerHidden] + private Joule(double val) : base(val, Units) { } + + public static implicit operator Joule(WattSecond self) + { + return Create(self.Value()); + } + + public static Joule operator +(Joule joule, WattSecond ws) + { + return Create(joule.Val + ws.Value()); + } + + public static Watt operator /(Joule joule, Second s) + { + return SIBase<Watt>.Create(joule.Val / s.Value()); + } + + public static JoulePerMeter operator /(Joule joule, Meter meter) + { + return SIBase<JoulePerMeter>.Create(joule.Val / meter.Value()); + } + } + + /// <summary> + /// SI Class for Watt [W]. + /// J = Ws + /// W = kgm^2/s^3 + /// </summary> + public class JoulePerKilogramm : SIBase<JoulePerKilogramm> + { + private static readonly int[] Units = { 0, 2, -2, 0, 0, 0, 0 }; + + private JoulePerKilogramm(double val) : base(val, Units) { } + + public static Joule operator *(Kilogram kg, JoulePerKilogramm jpg) + { + return SIBase<Joule>.Create(kg.Value() * jpg.Val); + } + } + + /// <summary> + /// SI Class for Joule per Meter [J/m]. + /// J = Ws + /// W = kgm^2/s^3 + /// </summary> + public class JoulePerMeter : SIBase<JoulePerMeter> + { + private static readonly int[] Units = { 1, 1, -2, 0, 0, 0, 0 }; + + [DebuggerHidden] + private JoulePerMeter(double val) : base(val, Units) { } + } + + /// <summary> + /// SI Class for one per second [1/s]. + /// </summary> + [DebuggerDisplay("rad/s: {Val} | rpm: {AsRPM}")] + public class PerSecond : SIBase<PerSecond> + { + private static readonly int[] Units = { 0, 0, -1, 0, 0, 0, 0 }; + + [DebuggerHidden] + private PerSecond(double val) : base(val, Units) { } + + [DebuggerHidden] + public static PerSquareSecond operator /(PerSecond perSecond, Second second) + { + return SIBase<PerSquareSecond>.Create(perSecond.Val / second.Value()); + } + + public double AsRPM + { + get { return Val * 60 / (2 * Math.PI); } + } + } + + /// <summary> + /// SI Class for Meter per second [m/s]. + /// </summary> + [DebuggerDisplay("{Val} | {AsKmph}")] + public class MeterPerSecond : SIBase<MeterPerSecond> + { + private static readonly int[] Units = { 0, 1, -1, 0, 0, 0, 0 }; + + [DebuggerHidden] + private MeterPerSecond(double val) : base(val, Units) { } + + public double AsKmph + { + get { return Val * 3.6; } + } + + /// <summary> + /// Implements the operator /. + /// </summary> + [DebuggerHidden] + public static PerSecond operator /(MeterPerSecond meterPerSecond, Meter meter) + { + return SIBase<PerSecond>.Create(meterPerSecond.Val / meter.Value()); + } + + /// <summary> + /// Implements the operator /. + /// </summary> + [DebuggerHidden] + public static Second operator /(MeterPerSecond meterPerSecond, MeterPerSquareSecond meterPerSquareSecond) + { + return SIBase<Second>.Create(meterPerSecond.Val / meterPerSquareSecond.Value()); + } + + /// <summary> + /// Implements the operator /. + /// </summary> + [DebuggerHidden] + public static MeterPerSquareSecond operator /(MeterPerSecond meterPerSecond, Second second) + { + return SIBase<MeterPerSquareSecond>.Create(meterPerSecond.Val / second.Value()); + } + + /// <summary> + /// Implements the operator *. + /// </summary> + [DebuggerHidden] + public static Meter operator *(MeterPerSecond meterPerSecond, Second second) + { + return SIBase<Meter>.Create(meterPerSecond.Val * second.Value()); + } + + /// <summary> + /// Implements the operator *. + /// </summary> + [DebuggerHidden] + public static MeterPerSquareSecond operator *(MeterPerSecond meterPerSecond, PerSecond perSecond) + { + return SIBase<MeterPerSquareSecond>.Create(meterPerSecond.Val * perSecond.Value()); + } + + /// <summary> + /// Implements the operator *. + /// </summary> + [DebuggerHidden] + public static Meter operator *(Second second, MeterPerSecond meterPerSecond) + { + return SIBase<Meter>.Create(second.Value() * meterPerSecond.Val); + } + } + + /// <summary> + /// SI Class for NewtonMeter [Nm]. + /// N = kgm/s^2 + /// </summary> + public class NewtonMeter : SIBase<NewtonMeter> + { + private static readonly int[] Units = { 1, 2, -2, 0, 0, 0, 0 }; + + [DebuggerHidden] + private NewtonMeter(double val) : base(val, Units) { } + + [DebuggerHidden] + public static Watt operator *(NewtonMeter newtonMeter, PerSecond perSecond) + { + return SIBase<Watt>.Create(newtonMeter.Val * perSecond.Value()); + } + + [DebuggerHidden] + public static Watt operator *(PerSecond perSecond, NewtonMeter newtonMeter) + { + return SIBase<Watt>.Create(perSecond.Value() * newtonMeter.Val); + } + + [DebuggerHidden] + public static Second operator /(NewtonMeter newtonMeter, Watt watt) + { + return SIBase<Second>.Create(newtonMeter.Val / watt.Value()); + } + + [DebuggerHidden] + public static PerSquareSecond operator /(NewtonMeter newtonMeter, KilogramSquareMeter kgKilogramSquareMeter) + { + return SIBase<PerSquareSecond>.Create(newtonMeter.Val / kgKilogramSquareMeter.Value()); + } + + [DebuggerHidden] + public static PerSecond operator /(NewtonMeter newtonMeter, NewtonMeterSecond newtonMeterSecond) + { + return SIBase<PerSecond>.Create(newtonMeter.Val / newtonMeterSecond.Value()); + } + + [DebuggerHidden] + public static Newton operator /(NewtonMeter newtonMeter, Meter meter) + { + return SIBase<Newton>.Create(newtonMeter.Val / meter.Value()); + } + + [DebuggerHidden] + public static NewtonMeterSecond operator /(NewtonMeter newtonMeter, PerSecond perSecond) + { + return SIBase<NewtonMeterSecond>.Create(newtonMeter.Val / perSecond.Value()); + } + } + + /// <summary> + /// SI Class for NewtonMeterSecond [Nms]. + /// N = kgm/s^2 + /// </summary> + public class NewtonMeterSecond : SIBase<NewtonMeterSecond> + { + private static readonly int[] Units = { 1, 2, -1, 0, 0, 0, 0 }; + private NewtonMeterSecond(double val) : base(val, Units) { } + } + + /// <summary> + /// SI Class for Amperer [A]. + /// </summary> + public class Ampere : SIBase<Ampere> + { + private static readonly int[] Units = { 0, 0, 0, 1, 0, 0, 0 }; + private Ampere(double val) : base(val, Units) { } + + public static Watt operator *(Ampere ampere, Volt volt) + { + return SIBase<Watt>.Create(volt.Value() * ampere.Val); + } + + public static Ampere operator *(Ampere ampere, double val) + { + return Create(ampere.Val * val); + } + + public static Volt operator /(Watt watt, Ampere ampere) + { + return SIBase<Volt>.Create(watt.Value() / ampere.Value()); + } + } + + /// <summary> + /// SI Class for Amperer [V]. + /// V = kgm^2/As^2 + /// </summary> + public class Volt : SIBase<Volt> + { + private static readonly int[] Units = { 1, 2, -2, -1, 0, 0, 0 }; + private Volt(double val) : base(val, Units) { } + + public static Watt operator *(Volt volt, Ampere ampere) + { + return SIBase<Watt>.Create(volt.Val * ampere.Value()); + } + + public static Ampere operator /(Watt watt, Volt volt) + { + return SIBase<Ampere>.Create(watt.Value() / volt.Value()); + } + } + + /// <summary> + /// Base Class for all special SI Classes. Not intended to be used directly. + /// Implements templated operators for type safety and convenience. + /// </summary> + /// <typeparam name="T"></typeparam> + public abstract class SIBase<T> : SI where T : SIBase<T> + { + private static readonly T ZeroPrototype; + + static SIBase() + { + const BindingFlags bindingFlags = BindingFlags.NonPublic | BindingFlags.Instance; + var constructorInfo = typeof(T).GetConstructor(bindingFlags, null, new[] { typeof(double) }, null); + var parameter = Expression.Parameter(typeof(double)); + var lambda = Expression.Lambda<Func<double, T>>(Expression.New(constructorInfo, parameter), parameter); + Constructor = lambda.Compile(); + ZeroPrototype = Constructor(0); + } + + /// <summary> + /// The constructor for the generic type T. + /// </summary> + private static readonly Func<double, T> Constructor; + + /// <summary> + /// Creates the specified special SI object. + /// </summary> + /// <param name="val">The value of the SI object.</param> + [DebuggerStepThrough] + public static T Create(double val) + { + if (val == 0) + { + return ZeroPrototype; + } + + return Constructor(val); + } + + [DebuggerStepThrough] + protected SIBase(double value, int[] units) : base(value, units) { } + + [DebuggerStepThrough] + public new T Abs() + { + return Create(Math.Abs(Val)); + } + + #region Operators + + /// <summary> + /// Implements the operator + for two specialized SI Classes. + /// </summary> + /// <param name="si1">The si1.</param> + /// <param name="si2">The si2.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator +(SIBase<T> si1, SIBase<T> si2) + { + return Create(si1.Val + si2.Val); + } + + /// <summary> + /// Implements the operator + for a specialized SI Class and a generic SI Class. + /// </summary> + /// <param name="si1">The si1.</param> + /// <param name="si2">The si2.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator +(SIBase<T> si1, SI si2) + { + return ((si1 as SI) + si2).Cast<T>(); + } + + /// <summary> + /// Implements the operator + for a generic SI Class and a specialized SI Class. + /// </summary> + /// <param name="si1">The si1.</param> + /// <param name="si2">The si2.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator +(SI si1, SIBase<T> si2) + { + return (si1 + (si2 as SI)).Cast<T>(); + } + + /// <summary> + /// Implements the unary operator -. + /// </summary> + /// <param name="si1">The si1.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator -(SIBase<T> si1) + { + return Create(-si1.Val); + } + + /// <summary> + /// Implements the operator - for two specialized SI classes. + /// </summary> + /// <param name="si1">The si1.</param> + /// <param name="si2">The si2.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator -(SIBase<T> si1, SIBase<T> si2) + { + return Create(si1.Val - si2.Val); + } + + /// <summary> + /// Implements the operator - for a specialized SI class and a generic SI class. + /// </summary> + /// <param name="si1">The si1.</param> + /// <param name="si2">The si2.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator -(SIBase<T> si1, SI si2) + { + return ((si1 as SI) - si2).Cast<T>(); + } + + /// <summary> + /// Implements the operator - for a generic SI class and a specialized SI class. + /// </summary> + /// <param name="si1">The si1.</param> + /// <param name="si2">The si2.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator -(SI si1, SIBase<T> si2) + { + return (si1 - (si2 as SI)).Cast<T>(); + } + + /// <summary> + /// Implements the operator * for a double and a specialized SI class. + /// </summary> + /// <param name="d">The double value.</param> + /// <param name="si">The si.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator *(double d, SIBase<T> si) + { + return Create(d * si.Val); + } + + /// <summary> + /// Implements the operator * for a specialized SI class and a double. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="d">The double.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator *(SIBase<T> si, double d) + { + return Create(si.Val * d); + } + + /// <summary> + /// Implements the operator / for a specialized SI class and a double. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="d">The double.</param> + /// <returns> + /// The result of the operator. + /// </returns> + [DebuggerHidden] + public static T operator /(SIBase<T> si, double d) + { + return Create(si.Val / d); + } + + [DebuggerHidden] + public static Scalar operator /(SIBase<T> si, SIBase<T> si2) + { + return SIBase<Scalar>.Create(si.Val / si2.Val); + } + + #endregion + } + + /// <summary> + /// Class for representing generic SI Units. + /// </summary> + /// <remarks> + /// Usage: new SI(1.0).Newton.Meter, new SI(2.3).Rounds.Per.Minute + /// </remarks> + [DebuggerDisplay("{Val}")] + public class SI : IComparable + { + /// <summary> + /// The basic scalar value of the SI. + /// </summary> + protected readonly double Val; + + /// <summary> + /// The array of the SI units. + /// </summary> + private readonly int[] _units; + + /// <summary> + /// Initializes a new instance of the <see cref="SI"/> class which allows to construct a new SI with all parameters. + /// </summary> + /// <param name="val">The value.</param> + /// <param name="units">The units.</param> + /// <param name="isMassParam"></param> + protected SI(double val, int[] units) + { + Val = val; + _units = units; + + if (double.IsNaN(Val)) + { + throw new VectoException("NaN [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); + } + + if (double.IsInfinity(Val)) + { + throw new VectoException("Infinity [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); + } + } + + public SI(UnitInstance si, double val = 0) : this(val * si.Factor, si.GetSIUnits()) + { + + } + + /// <summary> + /// Initializes a new instance of the <see cref="SI"/> class which copies the units from an already existing SI. + /// </summary> + /// <param name="val">The value.</param> + /// <param name="unit">The unit.</param> + [DebuggerHidden] + private SI(double val, SI unit) : this(val, unit._units) { } + + [DebuggerHidden] + private SI(SI si, double factor, int[] unitsParam) + { + Val = si.Val / factor; + _units = unitsParam; + + if (double.IsNaN(Val)) + { + throw new VectoException("NaN [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); + } + + if (double.IsInfinity(Val)) + { + throw new VectoException("Infinity [{0}] is not allowed for SI-Values in Vecto.", GetUnitString()); + } + } + + public SI ConvertTo(UnitInstance si) + { + + if (!SIUtils.CompareUnits(_units, si.GetSIUnits())) + { + throw new VectoException("Unit missing. Conversion not possible. [{0}] does not contain a [{1}].", GetUnitString(_units), si.GetSIUnits()); + } + + var factorValue = si.Factor; + return new SI(this, unitsParam: si.GetSIUnits(), factor: factorValue); + } + + /// <summary> + /// Casts the SI Unit to the concrete unit type (if the units allow such an cast). + /// </summary> + /// <typeparam name="T">the specialized SI unit. e.g. Watt, NewtonMeter, Second</typeparam> + [DebuggerHidden] + public T Cast<T>() where T : SIBase<T> + { + var si = ToBasicUnits(); + var t = SIBase<T>.Create(si.Val); + if (!si.HasEqualUnit(t)) + { + throw new VectoException("SI Unit Conversion failed: From {0} to {1}", si, t); + } + return t; + } + + /// <summary> + /// Converts the derived SI units to the basic units and returns this as a new SI object. + /// </summary> + public SI ToBasicUnits() + { + return new SI(Val, _units); + } + + + /// <summary> + /// Gets the underlying scalar double value. + /// </summary> + [DebuggerHidden] + public double Value() + { + return Val; + } + + /// <summary> + /// Clones this instance. + /// </summary> + public SI Clone() + { + return new SI(Val, _units); + } + + /// <summary> + /// Returns the absolute value. + /// </summary> + public SI Abs() + { + return new SI(Math.Abs(Val), this); + } + + /// <summary> + /// Returns the numerical sign of the SI. + /// </summary> + /// <returns>-1 if si < 0. 0 if si==0, 1 if si > 0.</returns> + [DebuggerHidden] + public int Sign() + { + return Math.Sign(Val); + } + + #region Operators + + [DebuggerHidden] + public static SI operator +(SI si1, SI si2) + { + if (!si1.HasEqualUnit(si2)) + { + throw new VectoException("Operator '+' can only operate on SI Objects with the same unit. Got: {0} + {1}", si1, si2); + } + + + return new SI(si1.Val + si2.Val, si1); + } + + [DebuggerHidden] + public static SI operator -(SI si1, SI si2) + { + if (!si1.HasEqualUnit(si2)) + { + throw new VectoException("Operator '-' can only operate on SI Objects with the same unit. Got: {0} - {1}", si1, si2); + } + return new SI(si1.Val - si2.Val, si1); + } + + [DebuggerHidden] + public static SI operator -(SI si1) + { + return new SI(-si1.Val, si1); + } + + public static SI operator *(SI si1, SI si2) + { + var unitArray = SIUtils.CombineUnits(si1._units, si2._units); + return new SI(si1.Val * si2.Val, unitArray); + } + + [DebuggerHidden] + public static SI operator *(SI si1, double d) + { + return new SI(si1.Val * d, si1); + } + + [DebuggerHidden] + public static SI operator *(double d, SI si1) + { + return new SI(d * si1.Val, si1); + } + + public static SI operator /(SI si1, SI si2) + { + double result; + try + { + result = si1.Val / (si2.Val); + + // bad cases: Infinity = x / 0.0 (for x != 0), NaN = 0.0 / 0.0 + if (double.IsInfinity(result) || double.IsNaN(result)) + { + throw new DivideByZeroException(); + } + } + catch (DivideByZeroException ex) + { + throw new VectoException( + string.Format("Can not compute division by zero ([{0}] / 0[{1}])", si1.GetUnitString(), si2.GetUnitString()), ex); + } + + var unitArray = SIUtils.CombineUnits(si1._units, SIUtils.MultiplyUnits(si2._units, -1)); + + return new SI(result, unitArray); + } + + [DebuggerHidden] + public static SI operator /(SI si1, double d) + { + if (d.IsEqual(0)) + { + throw new VectoException(string.Format("Can not compute division by zero ([{0}] / 0)", si1.GetUnitString()), new DivideByZeroException()); + } + + return new SI(si1.Val / d, si1); + } + + [DebuggerHidden] + public static SI operator /(double d, SI si1) + { + if (si1.IsEqual(0)) + { + throw new VectoException(string.Format("Can not compute division by zero (x / 0[{0}])", si1.GetUnitString()), + new DivideByZeroException()); + } + + return new SI(d / (si1.Val), si1._units.Select(u => -u).ToArray()); + } + + [DebuggerHidden] + public static bool operator <(SI si1, SI si2) + { + if (!si1.HasEqualUnit(si2)) + { + throw new VectoException("Operator '<' can only operate on SI Objects with the same unit. Got: {0} < {1}", si1, si2); + } + return si1.Val < si2.Val; + } + + [DebuggerHidden] + public static bool operator <(SI si1, double d) + { + return si1 != null && si1.Val < d; + } + + [DebuggerHidden] + public static bool operator >(SI si1, SI si2) + { + if (!si1.HasEqualUnit(si2)) + { + throw new VectoException("Operator '>' can only operate on SI Objects with the same unit. Got: {0} > {1}", si1, si2); + } + return si1.Val > si2.Val; + } + + [DebuggerHidden] + public static bool operator >(SI si1, double d) + { + return si1 != null && si1.Val > d; + } + + [DebuggerHidden] + public static bool operator >(double d, SI si1) + { + return si1 != null && d > si1.Val; + } + + [DebuggerHidden] + public static bool operator <(double d, SI si1) + { + return si1 != null && d < si1.Val; + } + + [DebuggerHidden] + public static bool operator <=(SI si1, SI si2) + { + if (!si1.HasEqualUnit(si2)) + { + throw new VectoException("Operator '<=' can only operate on SI Objects with the same unit. Got: {0} <= {1}", si1, + si2); + } + return si1.Val <= si2.Val; + } + + [DebuggerHidden] + public static bool operator <=(SI si1, double d) + { + return si1 != null && si1.Val <= d; + } + + [DebuggerHidden] + public static bool operator >=(SI si1, SI si2) + { + if (!si1.HasEqualUnit(si2)) + { + throw new VectoException("Operator '>=' can only operate on SI Objects with the same unit. Got: {0} >= {1}", si1, + si2); + } + return si1.Val >= si2.Val; + } + + [DebuggerHidden] + public static bool operator >=(SI si1, double d) + { + return si1 != null && si1.Val >= d; + } + + [DebuggerHidden] + public static bool operator >=(double d, SI si1) + { + return si1 != null && d >= si1.Val; + } + + [DebuggerHidden] + public static bool operator <=(double d, SI si1) + { + return si1 != null && d <= si1.Val; + } + + /// <summary> + /// Determines whether the SI is between lower and uppper bound. + /// </summary> + /// <param name="lower">The lower bound.</param> + /// <param name="upper">The upper bound.</param> + /// <returns></returns> + public bool IsBetween(SI lower, SI upper) + { + return lower <= Val && Val <= upper; + } + + /// <summary> + /// Determines whether the SI is between lower and upper bound. + /// </summary> + /// <param name="lower">The lower bound.</param> + /// <param name="upper">The upper bound.</param> + /// <returns></returns> + public bool IsBetween(double lower, double upper) + { + return lower <= Val && Val <= upper; + } + + #endregion + + #region ToString + + /// <summary> + /// Returns the Unit Part of the SI Unit Expression. + /// </summary> + public string GetUnitString(int[] units = null) + { + if (units == null) + { + units = _units; + } + return Unit.GetUnitString(units); + } + + public override string ToString() + { + return ToString(null); + } + + private string ToString(string format) + { + if (string.IsNullOrEmpty(format)) + { + format = "F4"; + } + + return string.Format(CultureInfo.InvariantCulture, "{0:" + format + "} [{2}]", Val, format, GetUnitString()); + } + + #endregion + + #region Equality members + + /// <summary> + /// Compares the Unit-Parts of two SI Units. + /// </summary> + /// <param name="si">The si.</param> + /// <returns></returns> + [DebuggerHidden] + public bool HasEqualUnit(SI si) + { + return SIUtils.CompareUnits(_units, si._units); + } + + /// <summary> + /// Determines whether the specified <see cref="System.Object" />, is equal to this instance. + /// </summary> + /// <param name="obj">The <see cref="System.Object" /> to compare with this instance.</param> + /// <returns> + /// <c>true</c> if the specified <see cref="System.Object" /> is equal to this instance; otherwise, <c>false</c>. + /// </returns> + public override bool Equals(object obj) + { + if (ReferenceEquals(null, obj)) + { + return false; + } + if (ReferenceEquals(this, obj)) + { + return true; + } + var other = obj as SI; + + var valFac = Val; + return other != null && valFac.Equals(other.Val) && HasEqualUnit(other); + } + + /// <summary> + /// Determines whether the specified si is equal. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + public bool IsEqual(SI si, SI tolerance = null) + { + var valFac = Val; + return (tolerance == null || HasEqualUnit(tolerance)) && HasEqualUnit(si) && valFac.IsEqual(si.Val, tolerance == null ? DoubleExtensionMethods.Tolerance : tolerance.Value()); + } + + /// <summary> + /// Determines whether the specified value is equal. + /// </summary> + /// <param name="val">The value.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + [DebuggerHidden] + public bool IsEqual(double val, double tolerance = DoubleExtensionMethods.Tolerance) + { + var valFac = Val; + return valFac.IsEqual(val, tolerance); + } + + /// <summary> + /// Determines whether the specified si is smaller. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + public bool IsSmaller(SI si, SI tolerance = null) + { + if (!HasEqualUnit(si)) + { + throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); + } + if (tolerance != null && !HasEqualUnit(tolerance)) + { + throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); + } + + var valFac = Val; + return valFac.IsSmaller(si.Val, tolerance == null ? DoubleExtensionMethods.Tolerance : tolerance.Value()); + } + + /// <summary> + /// Determines whether the specified si is smaller. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + public bool IsSmaller(SI si, double tolerance) + { + if (!HasEqualUnit(si)) + { + throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); + } + + var valFac = Val; + return valFac.IsSmaller(si.Val, tolerance); + } + + /// <summary> + /// Determines whether [is smaller or equal] [the specified si]. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + public bool IsSmallerOrEqual(SI si, SI tolerance = null) + { + if (!HasEqualUnit(si)) + { + throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); + } + if (tolerance != null && !HasEqualUnit(tolerance)) + { + throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); + } + + var valFac = Val; + + return valFac.IsSmallerOrEqual(si.Val, tolerance == null ? DoubleExtensionMethods.Tolerance : tolerance.Value()); + } + + /// <summary> + /// Determines whether the specified si is greater. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + public bool IsGreater(SI si, SI tolerance = null) + { + if (!HasEqualUnit(si)) + { + throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); + } + if (tolerance != null && !HasEqualUnit(tolerance)) + { + throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); + } + + var valFac = Val; + return valFac.IsGreater(si.Val, tolerance == null ? DoubleExtensionMethods.Tolerance : tolerance.Value()); + } + + /// <summary> + /// Determines whether the specified si is greater. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + [DebuggerStepThrough] + public bool IsGreater(SI si, double tolerance) + { + if (!HasEqualUnit(si)) + { + throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); + } + + var valFac = Val; + + return valFac.IsGreater(si.Val, tolerance); + } + + /// <summary> + /// Determines whether [is greater or equal] [the specified si]. + /// </summary> + /// <param name="si">The si.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + [DebuggerStepThrough] + public bool IsGreaterOrEqual(SI si, SI tolerance = null) + { + if (!HasEqualUnit(si)) + { + throw new VectoException("compared value has to be the same unit. Got: {0} <=> {1}", this, si); + } + if (tolerance != null && !HasEqualUnit(tolerance)) + { + throw new VectoException("tolerance has to be the same unit. Got: {0} <=> {1}", this, tolerance); + } + + var valFac = Val; + return valFac.IsGreaterOrEqual(si.Val, tolerance == null ? DoubleExtensionMethods.Tolerance : tolerance.Value()); + } + + /// <summary> + /// Determines whether the specified value is smaller. + /// </summary> + /// <param name="val">The value.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + [DebuggerStepThrough] + public bool IsSmaller(double val, double tolerance = DoubleExtensionMethods.Tolerance) + { + return Val.IsSmaller(val, tolerance); + } + + /// <summary> + /// Determines whether [is smaller or equal] [the specified value]. + /// </summary> + /// <param name="val">The value.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + [DebuggerStepThrough] + public bool IsSmallerOrEqual(double val, double tolerance = DoubleExtensionMethods.Tolerance) + { + return Val.IsSmallerOrEqual(val, tolerance); + } + + /// <summary> + /// Determines whether the specified value is greater. + /// </summary> + /// <param name="val">The value.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + [DebuggerStepThrough] + public bool IsGreater(double val, double tolerance = DoubleExtensionMethods.Tolerance) + { + return Val.IsGreater(val, tolerance); + } + + /// <summary> + /// Determines whether [is greater or equal] [the specified value]. + /// </summary> + /// <param name="val">The value.</param> + /// <param name="tolerance">The tolerance.</param> + /// <returns></returns> + [DebuggerStepThrough] + public bool IsGreaterOrEqual(double val, double tolerance = DoubleExtensionMethods.Tolerance) + { + return Val.IsGreaterOrEqual(val, tolerance); + } + + public override int GetHashCode() + { + unchecked + { + // ReSharper disable once NonReadonlyMemberInGetHashCode + var hashCode = Val.GetHashCode(); + hashCode = (hashCode * 397) ^ (_units != null ? _units.GetHashCode() : 0); + return hashCode; + } + } + + public int CompareTo(object obj) + { + var si = obj as SI; + if (si == null) + { + return 1; + } + + if (!HasEqualUnit(si)) + { + //if (SIUtils.GetnumberofSIUnits(si.Units) >= SIUtils.GetnumberofSIUnits(Units)) + if (si._units.Sum<int>(n => Math.Abs(n)) >= _units.Sum<int>(n => Math.Abs(n))) + { + return -1; + } + return 1; + } + + if (this > si) + { + return 1; + } + return this < si ? -1 : 0; + } + + public static bool operator ==(SI left, SI right) + { + return Equals(left, right); + } + + public static bool operator !=(SI left, SI right) + { + return !Equals(left, right); + } + + #endregion + + /// <summary> + /// Convert the SI to a string in the wished output format. + /// </summary> + /// <param name="decimals">The decimals.</param> + /// <param name="outputFactor">The output factor.</param> + /// <param name="showUnit">The show unit.</param> + /// <returns></returns> + public string ToOutputFormat(uint? decimals = null, double? outputFactor = null, bool? showUnit = null) + { + decimals = decimals ?? 4; + outputFactor = outputFactor ?? 1.0; + showUnit = showUnit ?? false; + + if (showUnit.Value) + { + return (Val * outputFactor.Value).ToString("F" + decimals.Value, CultureInfo.InvariantCulture) + " [" + + GetUnitString() + "]"; + } + + return (Val * outputFactor.Value).ToString("F" + decimals.Value, CultureInfo.InvariantCulture); + } + + public string ToGUIFormat() + { + return Val.ToGUIFormat(); + } + + public string ToXMLFormat(uint? decimals = null) + { + decimals = decimals ?? 2; + return Val.ToString("F" + decimals.Value, CultureInfo.InvariantCulture); + } + + public class EqualityComparer<T> : IEqualityComparer<T> where T : SI + { + private readonly double _precision; + + public EqualityComparer(double precision = DoubleExtensionMethods.Tolerance) + { + _precision = precision; + } + + public bool Equals(T x, T y) + { + return x.IsEqual(y.Value(), _precision); + } + + public int GetHashCode(T obj) + { + return obj.Value().GetHashCode(); + } + } + } } diff --git a/VectoCommon/VectoCommon/Utils/SIUtils.cs b/VectoCommon/VectoCommon/Utils/SIUtils.cs index aca1a1b905..fd2af019a9 100644 --- a/VectoCommon/VectoCommon/Utils/SIUtils.cs +++ b/VectoCommon/VectoCommon/Utils/SIUtils.cs @@ -2,454 +2,413 @@ namespace TUGraz.VectoCommon.Utils { - public struct SIUtils - { - public static bool CompareUnits(int[] units1, int[] units2) - { - for (var i = 0; i < units1.Length; i++) - { - if (units1[i] != units2[i]) - { - return false; - } - } - return true; - } - - public static int[] CombineUnits(int[] units1, int[] units2) - { - var units = new int[units1.Length]; - for (var i = 0; i < units1.Length; i++) - { - units[i] = units1[i] + units2[i]; - } - return units; - - } - - public static int[] MultiplyUnits(int[] units, int factor) - { - var result = new int[units.Length]; - for (var i = 0; i < units.Length; i++) - { - if (units[i] != 0) - { - result[i] = units[i] * factor; - } - } - return result; - } - } - - - public struct Unit - { - // TODO mk-2017-09-14: must be exact the same definition as in the SI class - find a way to de-duplicate this - private static readonly string[] Unitnames = { "kg", "m", "s", "A", "K", "mol", "cd" }; - - public static UnitInstance SI - { - get - { - return new UnitInstance(new[] { 0, 0, 0, 0, 0, 0, 0 }, 1, 1, 1); - } - } - - public static string GetUnitString(int[] siUnitParam, bool isGramm) - { - var numerator = ""; - var denominator = ""; - - for (var i = 0; i < siUnitParam.Length; i++) - { - var currentValue = siUnitParam[i]; - - var exponent = Math.Abs(currentValue); - var exponentStr = ""; - if (currentValue != 0) - { - var currentUnit = Unitnames[i]; - if (currentUnit == "kg" && isGramm) - { - currentUnit = "g"; - } - - if (exponent > 1) - { - exponentStr = "^" + exponent; - } - - if (currentValue > 0) - { - numerator += currentUnit + exponentStr; - - } - else if (currentValue < 0) - { - denominator += currentUnit + exponentStr; - } - } - } - string result; - - if (numerator == "") - { - if (denominator == "") - { - result = "-"; - } - else - { - result = "1/" + denominator; - } - } - else - { - if (denominator == "") - { - result = numerator; - } - else - { - result = numerator + "/" + denominator; - } - } - - return result; - } - } - - public struct UnitInstance - { - /// <summary> - /// kg, m, s, A, K, mol, cd - /// </summary> - private readonly int[] _units; - - private int _exponent; - private int _reciproc; - - [Flags] - public enum IsMass - { - IsKilo = 0x01, //0001 - IsGramm = 0x02, //0010 - IsKiloGramm = 0x04 //0100 - } - private IsMass _isMassOption; - - public double Factor { get; private set; } - - public UnitInstance(int[] units, double factor, int exponent, int reciproc) - { - _units = units; - Factor = factor; - _exponent = exponent; - _reciproc = reciproc; - _isMassOption = IsMass.IsKiloGramm; - } - - public IsMass GetGrammMode() - { - return _isMassOption; - } - - public int[] GetSIUnits() - { - return _units; - } - - /// <summary> - /// [g] (to basic unit: [kg]) - /// </summary> - public UnitInstance Gramm - { - get - { - _units[0] += 1 * _reciproc * _exponent; - - var factor = Math.Pow(1000, _reciproc * _exponent); - - if ((_isMassOption & IsMass.IsKilo) == IsMass.IsKilo) - { - //is Kilo -> Kilogramm are selected - _isMassOption = _isMassOption | ~IsMass.IsGramm; - _isMassOption = _isMassOption | IsMass.IsKiloGramm; - Factor /= factor; - } - else - { - //is not kilo -> Gramm are selected - _isMassOption = _isMassOption | IsMass.IsGramm; - _isMassOption = _isMassOption | ~IsMass.IsKiloGramm; - //factorValue *= factor; - } - _isMassOption = _isMassOption & ~IsMass.IsKilo; - - - //factorValue /= Math.Pow(1000, exponent * reciproc); - return this; // not work - } - } - - /// <summary> - /// Takes all following terms as cubic terms (=to the power of 3). - /// </summary> - public UnitInstance Cubic - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - _exponent = 3; - return this; - } - } - - /// <summary> - /// [s] Converts to/from Second. Internally everything is stored in seconds. - /// </summary> - public UnitInstance Hour - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - - var reciprocAndExponent = _reciproc * _exponent; - _units[2] += 1 * reciprocAndExponent; - - Factor *= Math.Pow(3600, reciprocAndExponent); - - return this; - } - } - - /// <summary> - /// Quantifier for Kilo (1000). - /// </summary> - public UnitInstance Kilo - { - get - { - _isMassOption = _isMassOption | IsMass.IsKilo; - Factor *= Math.Pow(1000, _exponent * _reciproc); - - return this; - } - } - - /// <summary> - /// [m] - /// </summary> - public UnitInstance Meter - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - _units[1] += 1 * _reciproc * _exponent; - return this; - } - } - - /// <summary> - /// Quantifier for milli (1/1000). - /// </summary> - public UnitInstance Milli - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - Factor /= Math.Pow(1000, _exponent * _reciproc); - return this; - } - } - - /// <summary> - /// Quantifier for Centi (1/100) - /// </summary> - public UnitInstance Centi - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - Factor /= Math.Pow(100, _exponent * _reciproc); - return this; - } - } - - /// <summary> - /// Quantifier for Dezi (1/10) - /// </summary> - public UnitInstance Dezi - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - Factor /= Math.Pow(10, _exponent * _reciproc); - return this; - } - } - - /// <summary> - /// [s] Converts to/from Second. Internally everything is stored in seconds. - /// </summary> - public UnitInstance Minute - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - var reciprocAndExponent = _reciproc * _exponent; - _units[2] += 1 * reciprocAndExponent; - Factor *= Math.Pow(60, reciprocAndExponent); - return this; - } - } - - /// <summary> - /// [N] - /// </summary> - public UnitInstance Newton - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - var reciprocAndExponent = _reciproc * _exponent; - _units[0] += 1 * reciprocAndExponent; - _units[1] += 1 * reciprocAndExponent; - _units[2] -= 2 * reciprocAndExponent; - - return this; - } - } - - /// <summary> - /// Defines the denominator by the terms following after the Per. - /// </summary> - public UnitInstance Per - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - _exponent = 1; - _reciproc = _reciproc * -1; - return this; - } - } - - /// <summary> - /// [-]. Defines radian. Only virtual. Has no real SI unit. - /// </summary> - public UnitInstance Radian - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - return this; - } - } - - /// <summary> - /// [-]. Converts to/from Radiant. Internally everything is stored in radian. - /// </summary> - public UnitInstance Rounds - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - Factor *= Math.Pow(2 * Math.PI, _exponent * _reciproc); - return this; - } - } - - /// <summary> - /// [s] - /// </summary> - public UnitInstance Second - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - _units[2] += 1 * _reciproc * _exponent; - return this; - } - } - - /// <summary> - /// Takes all following terms as quadratic terms (=to the power of 2). - /// </summary> - public UnitInstance Square - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - _exponent = 2; - return this; - } - } - - /// <summary> - /// [t] (to basic unit: [kg]) - /// </summary> - public UnitInstance Ton - { - get - { - // remove Gramm and Kilo and KiloGramm is selected. - _isMassOption = _isMassOption & ~IsMass.IsKilo; - _isMassOption = _isMassOption | ~IsMass.IsGramm; - _isMassOption = _isMassOption | IsMass.IsKiloGramm; - - var reciprocAndExponent = _reciproc * _exponent; - _units[0] += 1 * reciprocAndExponent; - Factor *= Math.Pow(1000, reciprocAndExponent); - - return this; - } - } - - /// <summary> - /// [W] - /// </summary> - public UnitInstance Watt - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - - var reciprocAndExponent = _reciproc * _exponent; - _units[0] += 1 * reciprocAndExponent; - _units[1] += 2 * reciprocAndExponent; - _units[2] -= 3 * reciprocAndExponent; - - return this; - } - } - public UnitInstance Joule - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - - var reciprocAndExponent = _reciproc * _exponent; - _units[0] += 1 * reciprocAndExponent; - _units[1] += 2 * reciprocAndExponent; - _units[2] -= 2 * reciprocAndExponent; - - return this; - } - } - - public UnitInstance Liter - { - get - { - _isMassOption = _isMassOption & ~IsMass.IsKilo; - - var reciprocAndExponent = _reciproc * _exponent; - _units[1] += 3 * reciprocAndExponent; - Factor /= Math.Pow(1000, reciprocAndExponent); - - return this; - } - } - } + public struct SIUtils + { + public static bool CompareUnits(int[] units1, int[] units2) + { + for (var i = 0; i < units1.Length; i++) + { + if (units1[i] != units2[i]) + { + return false; + } + } + return true; + } + + public static int[] CombineUnits(int[] units1, int[] units2) + { + var units = new int[units1.Length]; + for (var i = 0; i < units1.Length; i++) + { + units[i] = units1[i] + units2[i]; + } + return units; + + } + + public static int[] MultiplyUnits(int[] units, int factor) + { + var result = new int[units.Length]; + for (var i = 0; i < units.Length; i++) + { + if (units[i] != 0) + { + result[i] = units[i] * factor; + } + } + return result; + } + } + + + public struct Unit + { + // TODO mk-2017-09-14: must be exact the same definition as in the SI class - find a way to de-duplicate this + private static readonly string[] Unitnames = { "kg", "m", "s", "A", "K", "mol", "cd" }; + + public static UnitInstance SI + { + get + { + return new UnitInstance(new[] { 0, 0, 0, 0, 0, 0, 0 }, 1, 1, 1); + } + } + + public static string GetUnitString(int[] siUnitParam) + { + var numerator = ""; + var denominator = ""; + + for (var i = 0; i < siUnitParam.Length; i++) + { + var currentValue = siUnitParam[i]; + + var exponent = Math.Abs(currentValue); + var exponentStr = ""; + if (currentValue != 0) + { + var currentUnit = Unitnames[i]; + + if (exponent > 1) + { + exponentStr = "^" + exponent; + } + + if (currentValue > 0) + { + numerator += currentUnit + exponentStr; + + } + else if (currentValue < 0) + { + denominator += currentUnit + exponentStr; + } + } + } + string result; + + if (numerator == "") + { + if (denominator == "") + { + result = "-"; + } + else + { + result = "1/" + denominator; + } + } + else + { + if (denominator == "") + { + result = numerator; + } + else + { + result = numerator + "/" + denominator; + } + } + + return result; + } + } + + public struct UnitInstance + { + /// <summary> + /// kg, m, s, A, K, mol, cd + /// </summary> + private readonly int[] _units; + + private int _exponent; + private int _reciproc; + + public double Factor { get; private set; } + + public UnitInstance(int[] units, double factor, int exponent, int reciproc) + { + _units = units; + Factor = factor; + _exponent = exponent; + _reciproc = reciproc; + } + + public int[] GetSIUnits() + { + return _units; + } + + /// <summary> + /// [g] (to basic unit: [kg]) + /// </summary> + public UnitInstance Gramm + { + get + { + _units[0] += 1 * _reciproc * _exponent; + + // division because kg is the base unit (g/1000 = kg) + Factor /= Math.Pow(1000, _reciproc * _exponent); + + // todo mk-2017-10-02: visual studio displays wrong units - check if still not working + return this; + } + } + + /// <summary> + /// Takes all following terms as cubic terms (=to the power of 3). + /// </summary> + public UnitInstance Cubic + { + get + { + + _exponent = 3; + return this; + } + } + + /// <summary> + /// [s] Converts to/from Second. Internally everything is stored in seconds. + /// </summary> + public UnitInstance Hour + { + get + { + + + var reciprocAndExponent = _reciproc * _exponent; + _units[2] += 1 * reciprocAndExponent; + + Factor *= Math.Pow(3600, reciprocAndExponent); + + return this; + } + } + + /// <summary> + /// Quantifier for Kilo (1000). + /// </summary> + public UnitInstance Kilo + { + get + { + Factor *= Math.Pow(1000, _exponent * _reciproc); + + return this; + } + } + + /// <summary> + /// [m] + /// </summary> + public UnitInstance Meter + { + get + { + + _units[1] += 1 * _reciproc * _exponent; + return this; + } + } + + /// <summary> + /// Quantifier for milli (1/1000). + /// </summary> + public UnitInstance Milli + { + get + { + + Factor /= Math.Pow(1000, _exponent * _reciproc); + return this; + } + } + + /// <summary> + /// Quantifier for Centi (1/100) + /// </summary> + public UnitInstance Centi + { + get + { + + Factor /= Math.Pow(100, _exponent * _reciproc); + return this; + } + } + + /// <summary> + /// Quantifier for Dezi (1/10) + /// </summary> + public UnitInstance Dezi + { + get + { + + Factor /= Math.Pow(10, _exponent * _reciproc); + return this; + } + } + + /// <summary> + /// [s] Converts to/from Second. Internally everything is stored in seconds. + /// </summary> + public UnitInstance Minute + { + get + { + + var reciprocAndExponent = _reciproc * _exponent; + _units[2] += 1 * reciprocAndExponent; + Factor *= Math.Pow(60, reciprocAndExponent); + return this; + } + } + + /// <summary> + /// [N] + /// </summary> + public UnitInstance Newton + { + get + { + + var reciprocAndExponent = _reciproc * _exponent; + _units[0] += 1 * reciprocAndExponent; + _units[1] += 1 * reciprocAndExponent; + _units[2] -= 2 * reciprocAndExponent; + + return this; + } + } + + /// <summary> + /// Defines the denominator by the terms following after the Per. + /// </summary> + public UnitInstance Per + { + get + { + + _exponent = 1; + _reciproc = _reciproc * -1; + return this; + } + } + + /// <summary> + /// [-]. Defines radian. Only virtual. Has no real SI unit. + /// </summary> + public UnitInstance Radian + { + get + { + + return this; + } + } + + /// <summary> + /// [-]. Converts to/from Radiant. Internally everything is stored in radian. + /// </summary> + public UnitInstance Rounds + { + get + { + + Factor *= Math.Pow(2 * Math.PI, _exponent * _reciproc); + return this; + } + } + + /// <summary> + /// [s] + /// </summary> + public UnitInstance Second + { + get + { + + _units[2] += 1 * _reciproc * _exponent; + return this; + } + } + + /// <summary> + /// Takes all following terms as quadratic terms (=to the power of 2). + /// </summary> + public UnitInstance Square + { + get + { + + _exponent = 2; + return this; + } + } + + /// <summary> + /// [t] (to basic unit: [kg]) + /// </summary> + public UnitInstance Ton + { + get + { + var reciprocAndExponent = _reciproc * _exponent; + _units[0] += 1 * reciprocAndExponent; + Factor *= Math.Pow(1000, reciprocAndExponent); + + return this; + } + } + + /// <summary> + /// [W] + /// </summary> + public UnitInstance Watt + { + get + { + + + var reciprocAndExponent = _reciproc * _exponent; + _units[0] += 1 * reciprocAndExponent; + _units[1] += 2 * reciprocAndExponent; + _units[2] -= 3 * reciprocAndExponent; + + return this; + } + } + public UnitInstance Joule + { + get + { + + + var reciprocAndExponent = _reciproc * _exponent; + _units[0] += 1 * reciprocAndExponent; + _units[1] += 2 * reciprocAndExponent; + _units[2] -= 2 * reciprocAndExponent; + + return this; + } + } + + public UnitInstance Liter + { + get + { + + + var reciprocAndExponent = _reciproc * _exponent; + _units[1] += 3 * reciprocAndExponent; + Factor /= Math.Pow(1000, reciprocAndExponent); + + return this; + } + } + } } diff --git a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs index 61b87638f2..c563053744 100644 --- a/VectoCore/VectoCore/OutputData/IModalDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/IModalDataContainer.cs @@ -374,7 +374,6 @@ namespace TUGraz.VectoCore.OutputData var fcVolumePerMeter = fuelConsumptionFinal / data.FuelData.FuelDensity; // fcVolumePerMeter = [m^2] - //return fcVolumePerMeter.ConvertTo().Cubic.Dezi.Meter * 100.SI().Kilo.Meter; return fcVolumePerMeter.ConvertTo(Unit.SI.Square.Dezi.Meter) * 100.SI(Unit.SI.Kilo.Meter); } diff --git a/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs b/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs index b332560a68..d62335abe6 100644 --- a/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs +++ b/VectoCore/VectoCore/OutputData/SummaryDataContainer.cs @@ -418,11 +418,14 @@ namespace TUGraz.VectoCore.OutputData if (vehicleLoading != null && !vehicleLoading.IsEqual(0) && fcPer100lkm != null) { //row[FCFINAL_LITERPER100TKM] = fcPer100lkm / // vehicleLoading.ConvertTo().Ton; - row[FCFINAL_LITERPER100TKM] = fcPer100lkm / - vehicleLoading.ConvertTo(Unit.SI.Ton); + row[FCFINAL_LITERPER100TKM] = fcPer100lkm / vehicleLoading.ConvertTo(Unit.SI.Ton); } if (cargoVolume > 0 && fcPer100lkm != null) { row[FCFINAL_LiterPer100M3KM] = fcPer100lkm / cargoVolume; + + + + } } -- GitLab