///© ℗®™ www.amsteddigital.com
namespace OperationalTwins.DataLayer.Geometry.Units
{
/// <summary>
///
/// </summary>
public interface IUnit : Abstractions.Interface
{
System.Collections.Generic.IEnumerable<string> Symbols { get; } //Used with formatting
/// <summary>
/// A Number which represents a value from which a scalar value can be calculated from the TotalUnits member
/// </summary>
Number Constant { get; }
/// <summary>
/// A Number which represents the total amount of integral units of this instance
/// </summary>
Number TotalUnits { get; }
//MinValue, MaxValue
}
/// <summary>
/// The base class of all units or magnitudes.
/// <see cref="Abstractions.Abstraction"/>
/// <see cref="IUnit"/>
/// </summary>
/// <remarks>
/// Other implementations...
/// https://github.com/dotnet/corefx/issues/6831
/// https://github.com/JohanLarsson/Gu.Units/blob/master/Gu.Units/ElectricCharge.generated.cs
/// </remarks>
public abstract class UnitBase : Abstractions.Abstraction,
IUnit, System.IFormattable, System.IComparable<UnitBase>
{
#region Statics
///// <summary>
///// Has only 1 value
///// </summary>
//public static System.ValueType Unit => default;
/// <summary>
/// The <see cref="System.Globalization.RegionInfo"/> as retrieved from <see cref="System.Globalization.RegionInfo.CurrentRegion"/>
/// </summary>
public static readonly System.Globalization.RegionInfo CurrentRegion = System.Globalization.RegionInfo.CurrentRegion;
/// <summary>
/// Indicates if the <see cref="CurrentRegion"/> utilizes the Metric system of units.
/// </summary>
public static bool IsMetricSystem
{
get { return CurrentRegion.IsMetric; }
}
#endregion
//would allow the ability to add units of differing types without having to access the Units.. would also be doable via Extenions
public static class UnitBaseExtensions
{
//WithError
public static IdealUnit Add(UnitBase a, UnitBase b) => new(new IdealUnit(a.Constant, b).TotalUnits + new IdealUnit(b.Constant, a).TotalUnits);
public static IdealUnit Subtract(UnitBase a, UnitBase b) => new(new IdealUnit(a.Constant, b).TotalUnits - new IdealUnit(b.Constant, a).TotalUnits);
public static IdealUnit Multiply(UnitBase a, UnitBase b) => new(new IdealUnit(a.Constant, b).TotalUnits * new IdealUnit(b.Constant, a).TotalUnits);
public static IdealUnit Divide(UnitBase a, UnitBase b) => new(new IdealUnit(a.Constant, b).TotalUnits / new IdealUnit(b.Constant, a).TotalUnits);
public static IdealUnit Modulus(UnitBase a, UnitBase b) => new(new IdealUnit(a.Constant, b).TotalUnits % new IdealUnit(b.Constant, a).TotalUnits);
//public static IdealUnit Modulus(UnitBase a, UnitBase b) => new(new IdealUnit(a.Constant, b).TotalUnits % IdealUnit.Create(b.TotalUnits, b.Constant).TotalUnits);
}
#region Fields
/// <summary>
/// The symbols utilized by this instance
/// </summary>
abstract protected System.Collections.Generic.List<string> m_Symbols { get; }
/// <summary>
/// Defines the number used to scale other distances to this number.
/// Is the value for when <see cref="Units"/> = 1
/// </summary>
public Number Constant
{
get;
internal protected set;
}
/// <summary>
/// The <see cref="Number"/> associated.
/// </summary>
public Number Units
{
get;
protected set;
}
#endregion
#region Properties
/// <summary>
/// The <see cref="Constant"/> of this instance when required
/// Can be thought of as the Unit with no value and only defines itself.
/// </summary>
protected virtual System.ValueType Unit
{
get => Constant;
set => Constant = value switch
{
byte b => b,
double d => d,
float f => f,
short s => s,
ushort uS => uS,
System.Half h => (ushort)h,
int i => i,
uint uI => uI,
long l => l,
ulong uL => uL,
System.Numerics.Complex c => c,
System.Numerics.BigInteger b => b,
_ => (decimal)value
};
}
/// <summary>
/// The <see cref="Units"/> of this instance when required
/// </summary>
protected virtual System.ValueType Value
{
get => Units;
set => Units = value switch
{
byte b => b,
double d => d,
float f => f,
short s => s,
ushort uS => uS,
System.Half h => (ushort)h,
int i => i,
uint uI => uI,
long l => l,
ulong uL => uL,
System.Numerics.Complex c => c,
System.Numerics.BigInteger b => b,
_ => (decimal)value
};
}
/// <summary>
/// The symbols of this instance when required
/// </summary>
public System.Collections.Generic.IEnumerable<string> Symbols => m_Symbols.AsReadOnly();
/// <summary>
/// The product of <see cref="Units"/> and <see cref="Constant"/>.
/// </summary>
public Number TotalUnits
{
get
{
//More Flexible
//return Constant.ToDouble() > 1D ? Units.ToDouble() * Constant.ToDouble() : Units.ToDouble() / Constant.ToDouble();
return Units.ToDouble() * Constant.ToDouble();
}
}
/// <summary>
/// <see cref="Constant"/> over <see cref="Units"/>
/// </summary>
public Number InverseTotalUnits => ComplexUnits.ToComplex().Real; //Constant / Units;
/// <summary>
/// <see cref="Units"/> over <see cref="Constant"/>
/// </summary>
public Number CompleteUnits => ComplexUnits.ToComplex().Imaginary; //Units / Constant;
/// <summary>
/// <see cref="System.Numerics.Complex"/> with the real as <see cref="Units"/> and the imaginary as the <see cref="Constant"/>
/// </summary>
public Number ComplexUnits => new System.Numerics.Complex(Units, Constant);
#endregion
#region Methods
//IUnit protected
protected bool CompareUnit(UnitBase b) => Unit == b.Unit;
protected bool CompareValue(UnitBase b) => Value == b.Value;
//Comparable?
#endregion
#region IUnit
/// <summary>
///
/// </summary>
System.Collections.Generic.IEnumerable<string> IUnit.Symbols
{
get { return Symbols; }
}
/// <summary>
///
/// </summary>
Number IUnit.Constant
{
get { return Constant; }
}
#endregion
#region Constructor
/// <summary>
/// Constructs a new UnitBase with the given constant
/// </summary>
/// <param name="constant">The constant which when multiplied by the Units property represents a quantity</param>
public UnitBase(Number constant)
{
Constant = constant;
}
/// <summary>
/// Constructs a new UnitBase from another.
/// If the Constants of the two Units are the same the Units property is assigned, otherwise the Units is obtained by division of the other UnitBase's Units by this instances Constant.
/// </summary>
/// <param name="constant">The constant which when multiplied by the Units property represents a quantity</param>
/// <param name="other">Another Unit base</param>
public UnitBase(Number constant, UnitBase other)
: this(constant)
{
if (other.Constant != Constant)
{
//12 inches in 1 ft = 12 Inches
Units = Constant.ToDouble() / other.Units.ToDouble();
//12 % 1 = 0
Units += Constant.ToDecimal() % other.Units.ToDecimal();
}
else
Units = other.Units;
}
#endregion
/// <summary>
/// Will CompareUnit and CompareValue and return the difference if either are not equal otherwise 0.
/// </summary>
/// <param name="other"></param>
/// <returns></returns>
int System.IComparable<UnitBase>.CompareTo(UnitBase other) => CompareUnit(other) ? CompareValue(other) ? 0 : this.Constant - other.Constant : this.Units - other.Units;
protected string ToString(string join = " ")
{
return string.Concat(Units.ToString(), join, System.Linq.Enumerable.FirstOrDefault(m_Symbols));
}
public override string ToString()
{
return ToString(null);
}
string System.IFormattable.ToString(string format, System.IFormatProvider formatProvider)
{
return string.Format(formatProvider, format, ToString());
}
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public bool Equals(UnitBase obj) => obj.TotalUnits == obj.TotalUnits;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public override bool Equals(object obj) => obj is UnitBase ub && ub.Equals(this);
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public override int GetHashCode() => System.HashCode.Combine(Symbols.GetHashCode(), TotalUnits.GetHashCode());
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator ==(UnitBase a, UnitBase b) => a.TotalUnits == b.TotalUnits;
//a.Unit == b.Unit && a.Value == b.Value;
//a.Constant == b.Constant && a.Units == b.TotalUnits;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator !=(UnitBase a, UnitBase b) => a.TotalUnits != b.TotalUnits;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator ==(UnitBase a, Number b) => a.TotalUnits == b;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator !=(UnitBase a, Number b) => a.TotalUnits != b;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator >(UnitBase a, UnitBase b) => a.TotalUnits > b.TotalUnits;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator <(UnitBase a, UnitBase b) => a.TotalUnits < b.TotalUnits;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator >(UnitBase a, Number b) => a.TotalUnits > b;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator <(UnitBase a, Number b) => a.TotalUnits < b;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator <=(UnitBase a, UnitBase b) => a.TotalUnits <= b.TotalUnits;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator >=(UnitBase a, UnitBase b) => a.TotalUnits >= b.TotalUnits;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator <=(UnitBase a, Number b) => a.Equals(b) || a .Constant< b;
[System.Runtime.CompilerServices.MethodImpl(System.Runtime.CompilerServices.MethodImplOptions.AggressiveInlining)]
public static bool operator >=(UnitBase a, Number b) => a.Equals(b) || a.Constant > b;
//public static UnitBase operator +(UnitBase a, UnitBase b) => UnitBaseExtensions.Add(a, b);
//public static UnitBase operator -(UnitBase a, UnitBase b) => UnitBaseExtensions.Subtract(a, b);
//public static UnitBase operator *(UnitBase a, UnitBase b) => UnitBaseExtensions.Multiply(a, b);
//public static UnitBase operator /(UnitBase a, UnitBase b) => UnitBaseExtensions.Divide(a, b);
//Implementing operators is not really feasible at this level however it could be done in CoreUnits if that provides any meaning.
//Could also interoperate on Units whatever that would mean to who uses it.
//virtuals might actually help here but since there interfaces it makes little sense.
//https://github.com/dotnet/corefx/issues/6831#issuecomment-230557261
//To parse you can provide a static which can be exposed from the dervived types if they desire so.
static bool Parse(UnitBase units, string value, int offset = 0, int count = -1, char[] symbols = null, System.Globalization.NumberStyles ns = System.Globalization.NumberStyles.None, System.Globalization.NumberFormatInfo nfi = null)
{
if ((object.ReferenceEquals(units, null) || object.ReferenceEquals(units.Symbols, null)) &&
object.ReferenceEquals(units.Symbols, null) || string.IsNullOrWhiteSpace(value)) return false;
if (count < 0) count = value.Length - offset;
int symbolIndex = value.IndexOfAny(symbols ?? System.Linq.Enumerable.ToArray(System.Linq.Enumerable.SelectMany(units.Symbols, s => System.Linq.Enumerable.ToArray(s))), offset, count);
if (symbolIndex < 0 || symbolIndex > count) return false;
if (object.ReferenceEquals(units, null).Equals(false))
{
try
{
units.Units += Number.Parse(System.Text.Encoding.Default.GetBytes(value.ToCharArray(), symbolIndex, count), symbolIndex, count = value.Length - symbolIndex, System.Text.Encoding.Default, ns, nfi ?? System.Globalization.NumberFormatInfo.CurrentInfo);
}
catch
{
return false;
}
}
else
{
//Must check loaded types and get all Symbols...
throw new System.NotImplementedException();
}
return true;
}
}
/// <summary>
/// A layer of <see cref="IUnit"/>; the unit of indirection as well as an <see cref="Abstractions.Interface"/>
/// </summary>
public interface IndirectionUnit : IUnit, Abstractions.Interface
{
/// <summary>
/// The Error
/// </summary>
Number Error { get; }
}
/// <summary>
/// A unit which represents [within a small margin of error] itself. <see cref="IndirectionUnit"/>
/// </summary>
public class IdealUnit : UnitBase, IndirectionUnit
{
//Todo, allow min, max and symbols to be given
public static IdealUnit Create(Number value, Number constant) => new IdealUnit(value, new IdealUnit(constant));
/// <summary>
///
/// </summary>
public const double Zero = Common.Binary.DoubleZero,
One = 1.00000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001;
/// <summary>
/// The smallest and largest positive values.
/// </summary>
public static readonly IdealUnit MinValue = new IdealUnit(Number.SignedZero), MaxValue = new IdealUnit((Number)double.MaxValue);
//@Sprintf
static readonly System.Collections.Generic.List<string> IndirectUnitSymbols = new ()
{
"{{0}}"
};
/// <summary>
/// The Error
/// </summary>
internal protected Number Error;
/// <summary>
/// Create the;
/// </summary>
public IdealUnit()
: base(One)
{
Constant = MinValue.Constant;
Units = MinValue.Units;
Error = Zero;
}
/// <summary>
/// Create a;
/// </summary>
/// <param name="units"></param>
public IdealUnit(Number units)
: base(Zero)
{
Units = units;
Error = Zero;
}
/// <summary>
/// With <see cref="Error"/> as the <see cref="System.Numerics.Complex.Imaginary"/>
/// </summary>
/// <param name="units"></param>
public IdealUnit(System.Numerics.Complex units)
: base(Zero)
{
Units = units.Real;
Error = units.Imaginary;
}
/// <summary>
/// Create from;
/// </summary>
/// <param name="other"></param>
public IdealUnit(IdealUnit other) : base(One, other) { }
/// <summary>
/// <see cref="UnitBase"/>
/// </summary>
/// <param name="value"></param>
/// <param name="other"></param>
public IdealUnit(Number value, IdealUnit other)
: base(One, other)
{
Units = value;
Error = One;
}
/// <summary>
/// Create the, <see cref="UnitBase"/>
/// </summary>
/// <param name="constant"></param>
/// <param name="other"></param>
public IdealUnit(Number constant, UnitBase other) : base(constant, other)
{
}
/// <summary>
/// The symbol
/// </summary>
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return IndirectUnitSymbols;
}
}
//Use IdealUnit for conversions to other units and allow the error to be specified.
Number IndirectionUnit.Error
{
get { return this.Error; }
}
System.Collections.Generic.IEnumerable<string> IUnit.Symbols
{
get { return IndirectUnitSymbols; }
}
Number IUnit.Constant
{
get { return this.Constant; }
}
Number IUnit.TotalUnits
{
get { return this.TotalUnits; }
}
}
//One value
//ScalarUnit => IdealUnit
//Many values
//VectoralUnit => IdealUnit
/// <summary>
/// A form of <see cref="Unit"/> which represents values through bias.
/// </summary>
internal class VisceralUnit : IdealUnit
{
}
/// <summary>
/// A <see cref="IUnit"/> which contains an <see cref="Action"/> which is called by the <see cref="Sample"/> method.
/// </summary>
public class InformalUnit : IdealUnit
{
//IsError ()=> LastValue != 0 && LastValue >= 0x80000000
/// <summary>
/// Any <see cref="IUnit"/> which is conveyed from the <see cref="OnSample"/> method
/// </summary>
public IUnit LastValue;
/// <summary>
/// Typically used to compute a value or call a function
/// </summary>
System.Action OnSample = () => { };// = Common.Extensions.Delegate.ActionExtensions.NoOp;
/// <summary>
/// Stores the current instance in <see cref="LastValue"/> and calls <see cref="OnSample"/> which may modify this instance to pass values.
/// </summary>
public virtual void Sample()
{
LastValue = this;
try
{
OnSample();
}
catch
{
Error = this.TotalUnits;
}
}
}
/// <summary>
/// Subclass of <see cref="InformalUnit"/> with a <see cref="ValueType"/>
/// </summary>
public class InformationalUnit : InformalUnit
{
/// <summary>
/// Calls <see cref="InformalUnit.Sample"/> and then copies the result to <see cref="Value"/> as a <see cref="Double"/>
/// </summary>
public override void Sample()
{
try
{
base.Sample();
Value = this.TotalUnits;
}
catch
{
Error = this.TotalUnits.ToDouble();
}
}
}
/// <summary>
/// Class which is useful for measuring and converting distance
/// </summary>
public static class Distances
{
public interface IDistance : IUnit
{
Number TotalMeters { get; }
}
public class Distance : UnitBase, IDistance
{
//Should be Number to avoid readonly ValueType
public static readonly double PlanckLengthsPerMeter = 6.1873559 * System.Math.Pow(10, 34);
public static readonly double MilsPerMeter = 2.54 * System.Math.Pow(10, -5);
public const double InchesPerMeter = 0.0254;
public const double FeetPerMeter = 0.3048;
public const double YardsPerMeter = 0.9144;
public const double MilesPerMeter = 1609.344;
public static readonly double AttometersPerMeter = System.Math.Pow(10, 18);
//1 yoctometer = 0,001 zeptometer
//1 attometer = 1000 zeptometer
//1 000 yoctometer
//0,001 attometer
//10−21 meter
public static readonly double ZeptometersPerMeter = System.Math.Pow(10, -21);
public static readonly double YoctometersPerMeter = System.Math.Pow(10, -24);
public const double NanometersPerMeter = 1000000000;
public const double MicronsPerMeter = 1000000;
public const double MillimetersPerMeter = 1000;
public const double CentimetersPerMeter = 100;
public const double DecimetersPerMeter = 10;
public const double M = 1;
public const double KilometersPerMeter = 0.001;
/// <summary>
/// The minimum distance in Meters = The Planck Length
/// </summary>
public static readonly Distance MinValue = Common.Physics.ℓP;
public static readonly Distance PositiveInfinity = new Distance(Number.PositiveInfinty);
public static readonly Distance NegitiveInfinity = new Distance(Number.NegitiveInfinity);
public static readonly Distance Zero = new Distance(Number.Zero);
static readonly System.Collections.Generic.IList<string> DistanceSymbols = new System.Collections.Generic.List<string>()
{
"ℓP",
"mil",
"in",
"ft",
"yd",
"mi",
"n",
"µ",
"mm",
"cm",
"m",
"km"
}.AsReadOnly();
public Distance()
: base(M)
{
Constant = MinValue.Constant;
Units = MinValue.Units;
}
public Distance(Number meters)
: base(M)
{
Units = meters;
}
public Distance(Distance other) : base(M, other) { }
public Distance(Number value, Distance other) : base(M, other) { Units = value; }
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(DistanceSymbols);
}
}
public virtual Number TotalMeters
{
get { return Units; }
}
public virtual Number TotalInches
{
get { return TotalMeters / InchesPerMeter; }
}
public virtual Number TotalFeet
{
get { return TotalMeters / FeetPerMeter; }
}
public virtual Number TotalYards
{
get { return TotalMeters / YardsPerMeter; }
}
public virtual Number TotalKilometers
{
get { return TotalMeters / KilometersPerMeter; }
}
public static Distance FromInches(Number value)
{
return new Distance(value.ToDouble() * InchesPerMeter);
}
public static Distance FromFeet(Number value)
{
return new Distance(value.ToDouble() * FeetPerMeter);
}
public static Distance FromYards(Number value)
{
return new Distance(value.ToDouble() * YardsPerMeter);
}
public static Distance operator +(Distance a, int amount)
{
return new Distance(a.Units.ToDouble() + amount);
}
public static Distance operator -(Distance a, int amount)
{
return new Distance(a.Units.ToDouble() - amount);
}
public static Distance operator *(Distance a, int amount)
{
return new Distance(a.Units.ToDouble() * amount);
}
public static Distance operator /(Distance a, int amount)
{
return new Distance(a.Units.ToDouble() / amount);
}
public static Distance operator %(Distance a, int amount)
{
return new Distance(a.Units.ToDouble() % amount);
}
public static bool operator >(Distance a, IDistance b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalMeters;
return a.Units > b.TotalMeters;
}
public static bool operator <(Distance a, IDistance b)
{
return (a > b).Equals(false);
}
public static bool operator ==(Distance a, IDistance b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalMeters;
return a.Units == b.TotalMeters;
}
public static bool operator !=(Distance a, IDistance b)
{
return (a == b).Equals(false);
}
public override bool Equals(object obj)
{
if (obj is IDistance) return obj as IDistance == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
}
}
/// <summary>
/// Class which is usefl for measuring and converting frequency
/// </summary>
public static class Frequencies
{
//// public enum FrequencyKind
//// {
//// Local,
//// Universal
//// }
//// public static class Clock
//// {
//// }
public interface IFrequency
{
Number TotalMegahertz { get; }
}
//http://en.wikipedia.org/wiki/Frequency
/* Frequencies not expressed in hertz:
*
* Even higher frequencies are believed to occur naturally,
* in the frequencies of the quantum-mechanical wave functions of high-energy
* (or, equivalently, massive) particles, although these are not directly observable,
* and must be inferred from their interactions with other phenomena.
* For practical reasons, these are typically not expressed in hertz,
* but in terms of the equivalent quantum energy, which is proportional to the frequency by the factor of Planck's constant.
*/
public class Frequency : UnitBase, IFrequency
{
public static implicit operator double(Frequency t) { return t.Units.ToDouble(); }
public static implicit operator Frequency(double t) { return new Frequency(t); }
public static readonly Frequency Zero = new Frequency(Number.Zero);
public static readonly Frequency One = new Frequency(new Number(Hz)); //Hz
//Should be Number to avoid readonly ValueType
public const double Hz = 1;
public const double KHz = 1000D;
public const double MHz = 1000000D;
public const double GHz = 1000000000D;
public const double THz = 1000000000000D;
//http://en.wikipedia.org/wiki/Visible_spectrum - Audible?
public static bool IsVisible(Frequency f, double min = 430, double max = 790)
{
double F = f.Terahertz.ToDouble();
return F >= min && F <= max;
}
static readonly System.Collections.Generic.IList<string> FrequencySymbols = new System.Collections.Generic.List<string>()
{
"Hz",
"KHz",
"MHz",
"GHz",
"THz"
}.AsReadOnly();
public Frequency()
: base(Hz)
{
//Constant = MinValue.Constant;
//Units = MinValue.Units;
}
public Frequency(double MHz)
: base(Hz)
{
Units = MHz;
}
public Frequency(Frequency other) : base(Hz, other) { }
public Frequency(Number value, Frequency other) : base(Hz, other) { Units = value; }
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(FrequencySymbols);
}
}
public System.TimeSpan Period
{
get
{
return System.TimeSpan.FromSeconds(TotalHertz);
}
}
public virtual Number TotalHertz
{
get { return Units; }
}
public virtual Number TotalKilohertz
{
get { return TotalHertz * KHz; }
}
public virtual Number TotalMegahertz
{
get { return TotalHertz * MHz; }
}
public virtual Number TotalGigahertz
{
get { return TotalHertz * GHz; }
}
public virtual Number Terahertz
{
get { return TotalHertz * THz; }
}
public static Frequency FromKilohertz(Number value)
{
return new Frequency(value.ToDouble() * KHz);
}
public static Frequency FromMegahertz(Number value)
{
return new Frequency(value.ToDouble() * MHz);
}
public static Frequency FromGigahertz(Number value)
{
return new Frequency(value.ToDouble() * GHz);
}
public static Frequency FromTerahertz(Number value)
{
return new Frequency(value.ToDouble() * THz);
}
public static Frequency operator +(Frequency a, int amount)
{
return new Frequency(a.Units.ToDouble() + amount);
}
public static Frequency operator -(Frequency a, int amount)
{
return new Frequency(a.Units.ToDouble() - amount);
}
public static Frequency operator *(Frequency a, int amount)
{
return new Frequency(a.Units.ToDouble() * amount);
}
public static Frequency operator /(Frequency a, int amount)
{
return new Frequency(a.Units.ToDouble() / amount);
}
public static Frequency operator %(Frequency a, int amount)
{
return new Frequency(a.Units.ToDouble() % amount);
}
public static bool operator >(Frequency a, Frequency b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalUnits;
return a.Units > b.TotalUnits;
}
public static bool operator <(Frequency a, Frequency b)
{
return !(a > b);
}
public static bool operator <=(Frequency a, Frequency b) => a == b || a < b;
public static bool operator >=(Frequency a, Frequency b) => a == b || a > b;
public static bool operator ==(Frequency a, Frequency b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalUnits;
return a.Units == b.TotalUnits;
}
public static bool operator !=(Frequency a, Frequency b)
{
return !(a == b);
}
public override bool Equals(object obj)
{
if (obj is Frequency) return true;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
//Add methods for conversion to time
//http://www.hellspark.com/dm/ebench/tools/Analog_Oscilliscope/tutorials/scope_notes_from_irc.html
}
//// public struct Date
//// {
//// pulic DateTime ToDateTime(Frequency? time = null);
//// }
}
/// <summary>
/// Class which is useful for measuring and converting temperature
/// </summary>
public static class Temperatures
{
public interface ITemperature : IUnit
{
Number TotalCelcius { get; }
}
public class Temperature : UnitBase, ITemperature
{
public static implicit operator double(Temperature t) { return t.Units.ToDouble(); }
public static implicit operator Temperature(double t) { return new Temperature(t); }
public static readonly Temperature MinValue = 0D;
public static readonly Temperature One = 1D; //Celcius
const double FahrenheitMultiplier = 1.8;
public const double Fahrenheit = 32D;
public const double Kelvin = 273.15D;
public const char Degrees = '°';
static readonly System.Collections.Generic.IList<string> TempratureSymbols = new System.Collections.Generic.List<string>()
{
"C",
"F",
"K",
}.AsReadOnly();
public Temperature()
: base(One.Units)
{
//Constant = MinValue.Constant;
//Units = MinValue.Units;
}
public Temperature(double celcius)
: base(One.Units)
{
Units = celcius;
}
public Temperature(Temperature other) : base(One.Units, other) { }
public Temperature(Number value, Temperature other) : base(One.Units, other) { Units = value; }
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(TempratureSymbols);
}
}
public virtual Number TotalCelcius
{
get { return Units; }
}
public virtual Number TotalKelvin
{
get { return TotalCelcius + Kelvin; }
}
public virtual Number TotalFahrenheit
{
get { return TotalCelcius * FahrenheitMultiplier + Fahrenheit; }
}
public static Temperature FromFahrenheit(Number value)
{
return new Temperature(value.ToDouble() * Fahrenheit);
}
public static Temperature FromKelvin(Number value)
{
return new Temperature(value.ToDouble() - Kelvin);
}
public static Temperature operator +(Temperature a, int amount)
{
return new Temperature(a.Units.ToDouble() + amount);
}
public static Temperature operator -(Temperature a, int amount)
{
return new Temperature(a.Units.ToDouble() - amount);
}
public static Temperature operator *(Temperature a, int amount)
{
return new Temperature(a.Units.ToDouble() * amount);
}
public static Temperature operator /(Temperature a, int amount)
{
return new Temperature(a.Units.ToDouble() / amount);
}
public static Temperature operator %(Temperature a, int amount)
{
return new Temperature(a.Units.ToDouble() % amount);
}
public static bool operator >(Temperature a, ITemperature b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalUnits;
return a.Units > b.TotalUnits;
}
public static bool operator <(Temperature a, ITemperature b)
{
return !(a > b);
}
public static bool operator <=(Temperature a, ITemperature b) => a == b || a < b;
public static bool operator >=(Temperature a, ITemperature b) => a == b || a > b;
public static bool operator ==(Temperature a, ITemperature b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalUnits;
return a.Units == b.TotalUnits;
}
public static bool operator !=(Temperature a, ITemperature b)
{
return !(a == b);
}
public override bool Equals(object obj)
{
if (obj is ITemperature t) return (UnitBase)t == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
public override string ToString()
{
return ToString(" " + Degrees);
}
}
}
/// <summary>
/// A description of mass with respect to physical and mathematical properties.
/// </summary>
public static class Masses
{
public interface IMass : IUnit
{
Number TotalKilograms { get; }
}
public class Mass : UnitBase, IMass
{
//Should be Number to avoid readonly ValueType
public const double AtomicMassesPerKilogram = 6.022136652e+26;
public const double OuncesPerKilogram = 35.274;
public const double PoundsPerKilogram = 2.20462;
public const double Kg = 1;
public const double GramsPerKilogram = 1000;
static readonly System.Collections.Generic.IList<string> MassSymbols = new System.Collections.Generic.List<string>()
{
"u",
"o",
"lb",
"kg",
"g",
}.AsReadOnly();
public Mass()
: base(Kg)
{
//Constant = MinValue.Constant;
//Units = MinValue.Units;
}
public Mass(Number kiloGrams)
: base(Kg)
{
Units = kiloGrams;
}
public Mass(Mass other) : base(Kg, other) { }
public Mass(Number value, Mass other) : base(Kg, other) { Units = value; }
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(MassSymbols);
}
}
public virtual Number TotalKilograms
{
get { return Units; }
}
public virtual Number TotalAtomicMasses
{
get { return TotalKilograms * AtomicMassesPerKilogram; }
}
public virtual Number TotalGrams
{
get { return TotalKilograms * GramsPerKilogram; }
}
public virtual Number TotalOunces
{
get { return TotalKilograms * OuncesPerKilogram; }
}
public virtual Number TotalPounds
{
get { return TotalKilograms * PoundsPerKilogram; }
}
public static Mass FromGrams(Number value)
{
return new Mass(value.ToDouble() * GramsPerKilogram);
}
public static Mass FromPounds(Number value)
{
return new Mass(value.ToDouble() * PoundsPerKilogram);
}
public static Mass FromOunces(Number value)
{
return new Mass(value.ToDouble() * OuncesPerKilogram);
}
public static Mass FromAtomicMasses(Number value)
{
return new Mass(value.ToDouble() * AtomicMassesPerKilogram);
}
public static Mass operator +(Mass a, int amount)
{
return new Mass(a.Units.ToDouble() + amount);
}
public static Mass operator -(Mass a, int amount)
{
return new Mass(a.Units.ToDouble() - amount);
}
public static Mass operator *(Mass a, int amount)
{
return new Mass(a.Units.ToDouble() * amount);
}
public static Mass operator /(Mass a, int amount)
{
return new Mass(a.Units.ToDouble() / amount);
}
public static Mass operator %(Mass a, int amount)
{
return new Mass(a.Units.ToDouble() % amount);
}
public static bool operator >(Mass a, IMass b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalUnits;
return a.Units > b.TotalUnits;
}
public static bool operator <(Mass a, IMass b)
{
return (a > b).Equals(false);
}
//<=, >=
public static bool operator ==(Mass a, IMass b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalUnits;
return a.Units == b.TotalUnits;
}
public static bool operator !=(Mass a, IMass b)
{
return a.Equals(b).Equals(false);
}
public override bool Equals(object obj)
{
if (obj is IMass) return true;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
}
}
/// <summary>
/// A description of energy with respect to physical and mathematical properties.
/// </summary>
public static class Energies
{
/// <summary>
/// The interface of the <see cref="IUnit"/> which describes conversions to and from energy.
/// </summary>
public interface IEnergy : IUnit
{
/// <summary>
/// Gets the <see cref="Number"/> which implies the total joules of the energy
/// </summary>
Number TotalJoules { get; }
//Number TotalNewtons { get; }
//TotalCharge or TotalColumbs is useful
//ToDistance
//ToWavelength
//Etc
}
/// <summary>
/// A representation of energy in the form of math.
/// This class can be useful for converting a <see cref="IUnit"/> to <see cref="IEnergy"/> for calulcations.
/// <seealso href="https://en.wikipedia.org/wiki/Erg">Erg</seealso>, This class can be sub-classed or composed to define other units.
/// </summary>
public class Energy : UnitBase, IEnergy
{
public static implicit operator double(Energy t) { return t.Units.ToDouble(); }
public static implicit operator Energy(double t) { return new Energy(t); }
/// <summary>
/// `(-0)`
/// </summary>
/// <remarks>
/// Where as 0 would imply infinite `time` but not `frequency` and make such diambiguation quite difficult. (∞)
/// </remarks>
public static readonly Energy MinValue = -0D;
/// <summary>
/// `1`
/// </summary>
public static readonly Energy One = Joule;
/// <summary>
/// `0`
/// </summary>
public static readonly Energy Zero = 0D;
//Should be Number to avoid readonly ValueType
public const double ITUCaloriesPerJoule = 0.23884589663;
public const double BtusPerJoule = 0.00094781707775;
public const double ThermochemicalBtusPerJoule = 0.00094845138281;
public const double DekajoulesPerJoule = 0.1;
public const double NanojoulesPerJoule = 1e+9;
//* 0.0000001 Converts from erg to Newtons | Joule
public const double ErgPerJoule = 1e+7;
public const double Joule = 1;
public const double ExajoulesPerJoule = 1.0e-18;
public const double TerajoulesPerJoule = 1.0e-12;
public const double DecijoulesPerJoule = 10;
public const double CentijoulesPerJoule = 100;
public const double TeraelectronvoltsPerJoule = 6241506.48;
public const double FootPoundsPerJoule = 1.356;
//public const double USThermoPerJoule = 1.055e+8
public const double FemtojoulesPerJoule = 1000000000000000;
public const double AuttojoulePerJoule = 1000000000000000000;
static readonly System.Collections.Generic.IList<string> EnergySymbols = new System.Collections.Generic.List<string>()
{
"J",
//"Btu",
}.AsReadOnly();
public Energy(double joules)
: this(new Number(joules))
{
}
public Energy()
: base(Joule) { }
public Energy(Energy other) : base(Joule, other) { }
public Energy(Number joules)
: base(Joule)
{
Units = joules;
}
/// <summary>
/// Converts a corresponding <see cref="Masses.IMass"/> to Erg or <see cref="IEnergy"/>
/// </summary>
/// <param name="m"></param>
public Energy(Masses.IMass m) :
this(System.Math.Pow(m.TotalKilograms.ToDouble() * Velocities.Velocity.MaxValue.TotalMetersPerSecond.ToDouble(), 2))
{
}
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(EnergySymbols);
}
}
public Number ToalNanojoules
{
get { return TotalJoules * NanojoulesPerJoule; }
}
public Number TotalJoules
{
get { return Units; }
}
public Number Decijoules
{
get { return TotalJoules / DecijoulesPerJoule; }
}
public Number Dekajoules
{
get { return TotalJoules / DekajoulesPerJoule; }
}
public Number TotalErg
{
get { return TotalJoules * 1e+7; }
}
public Number Kilojoules
{
get { return TotalJoules * 1000; }
}
public Number TotalITUCalories
{
get { return TotalJoules / ITUCaloriesPerJoule; }
}
public static Energy FromITUCaloriesPerJoule(Number value)
{
return new Energy(value.ToDouble() * ITUCaloriesPerJoule);
}
public static Energy FromDekajoules(Number value)
{
return new Energy(value.ToDouble() * DekajoulesPerJoule);
}
public static Energy operator +(Energy a, int amount)
{
return new Energy(a.Units.ToDouble() + amount);
}
public static Energy operator -(Energy a, int amount)
{
return new Energy(a.Units.ToDouble() - amount);
}
public static Energy operator *(Energy a, int amount)
{
return new Energy(a.Units.ToDouble() * amount);
}
public static Energy operator /(Energy a, int amount)
{
return new Energy(a.Units.ToDouble() / amount);
}
public static Energy operator %(Energy a, int amount)
{
return new Energy(a.Units.ToDouble() % amount);
}
public static bool operator >(Energy a, IEnergy b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalUnits;
return a.Units > b.TotalUnits;
}
public static bool operator <(Energy a, IEnergy b)
{
return (a > b).Equals(false);
}
public static bool operator <=(Energy a, IEnergy b) => a == b || a < b;
public static bool operator >=(Energy a, IEnergy b) => a == b || a > b;
public static bool operator ==(Energy a, IEnergy b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalUnits;
return a.Units == b.TotalUnits;
}
public static bool operator !=(Energy a, IEnergy b)
{
return (a == b).Equals(false);
}
//public static Energy operator ~(Energy a)
//{
// throw new NotImplementedException();
//}
//public static Energy operator !(Energy a)
//{
// throw new NotImplementedException();
//}
//public static Energy operator &(Energy a, Energy b)
//{
// throw new NotImplementedException();
//}
//public static Energy operator |(Energy a, Energy b)
//{
// throw new NotImplementedException();
//}
//public static Energy operator <<(Energy a, int f)
//{
// throw new NotImplementedException();
//}
//public static Energy operator >>(Energy a, int f)
//{
// throw new NotImplementedException();
//}
public override bool Equals(object obj)
{
if (obj is IEnergy) return obj as IEnergy == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
}
///// <summary>
///// An example derivation of <see cref="Energy"/> in Nanojoules.
///// This example would be more succinct as 2 methods within Energy which should be a partial class. (ToNanoEnergy, FromNanoEnergy)
///// </summary>
//public class NanoEnergy : Energy
//{
// public static implicit operator double(NanoEnergy t) { return t.Units.ToDouble(); }
// public static implicit operator NanoEnergy(double t) { return new NanoEnergy(t); }
// /// <summary>
// /// `(-0)`
// /// </summary>
// /// <remarks>
// /// Where as 0 would imply infinite `time` but not `frequency` and make such diambiguation quite difficult. (∞)
// /// </remarks>
// public new static readonly NanoEnergy MinValue = -0D;
// /// <summary>
// /// `1`
// /// </summary>
// public new static readonly NanoEnergy One = Energy.NanojoulesPerJoule;
// /// <summary>
// /// `0`
// /// </summary>
// public new static readonly NanoEnergy Zero = 0D;
// /// <summary>
// /// Constructs a new instance
// /// </summary>
// /// <param name="nanoJoules"></param>
// public NanoEnergy(double nanoJoules) : base(nanoJoules / Energy.NanojoulesPerJoule)
// {
// }
// /// <summary>
// /// Constructs a new instance
// /// </summary>
// /// <param name="energy"></param>
// public NanoEnergy(Energy energy) : base(energy.TotalJoules * Energy.NanojoulesPerJoule) { }
//}
}
/// <summary>
/// A class which is useful for describing velocity.
/// </summary>
public static class Velocities
{
public interface IVelocity : IUnit
{
Number TotalMetersPerSecond { get; }
}
/// <summary>
/// A class which is useful for calculations involing speed / velocity
/// </summary>
public class Velocity : UnitBase, IVelocity
{
//Should be Number to avoid readonly ValueType
public const double FeetPerSecond = 3.28084;
public const double MilesPerHour = 2.23694;
public const double KilometersPerHour = 3.6;
public const double Knots = 1.94384;
public const double MetersPerSecond = 1;
public static readonly Velocity MaxValue = new Velocity(Common.Physics.c);//the speed of light = 299 792 458 meters per second
static readonly System.Collections.Generic.IList<string> VelocitySymbols = new System.Collections.Generic.List<string>()
{
"mph",
"fps",
"kph",
"mps",
}.AsReadOnly();
public Velocity()
: base(MetersPerSecond) { }
public Velocity(Number metersPerSecond)
: base(MetersPerSecond)
{
Units = metersPerSecond;
}
public Velocity(Velocity other) : base(MetersPerSecond, other) { }
public Velocity(Number value, Velocity other) : base(MetersPerSecond, other) { Units = value; }
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(VelocitySymbols);
}
}
//Todo, virtual not needed with interface.
public virtual Number TotalMetersPerSecond
{
get { return Units; }
}
public virtual Number TotalMilesPerHour
{
get { return TotalMetersPerSecond * MilesPerHour; }
}
public virtual Number TotalFeetPerSecond
{
get { return TotalMetersPerSecond * FeetPerSecond; }
}
public virtual Number TotalKilometersPerHour
{
get { return TotalMetersPerSecond * KilometersPerHour; }
}
public static Velocity FromKnots(Number value)
{
return new Velocity(value.ToDouble() * Knots);
}
public static Velocity operator +(Velocity a, int amount)
{
return new Velocity(a.Units.ToDouble() + amount);
}
public static Velocity operator -(Velocity a, int amount)
{
return new Velocity(a.Units.ToDouble() - amount);
}
public static Velocity operator *(Velocity a, int amount)
{
return new Velocity(a.Units.ToDouble() * amount);
}
public static Velocity operator /(Velocity a, int amount)
{
return new Velocity(a.Units.ToDouble() / amount);
}
public static Velocity operator %(Velocity a, int amount)
{
return new Velocity(a.Units.ToDouble() % amount);
}
public static bool operator >(Velocity a, IVelocity b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalUnits;
return a.Units > b.TotalUnits;
}
public static bool operator <(Velocity a, IVelocity b)
{
return !(a > b);
}
public static bool operator ==(Velocity a, IVelocity b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalUnits;
return a.Units == b.TotalUnits;
}
public static bool operator !=(Velocity a, IVelocity b)
{
return !(a == b);
}
public override bool Equals(object obj)
{
if (obj is IVelocity) return obj as IVelocity == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
}
}
/// <summary>
/// A class which is useful for describing forces in newtons
/// </summary>
public static class Forces
{
/// <summary>
/// An interface which provides access to the <see cref="TotalNewtons"/> of the <see cref="IForce"/>
/// </summary>
public interface IForce : IUnit
{
/// <summary>
/// </summary>
Number TotalNewtons { get; }
}
/// <summary>
/// A class which is usefl for representing and converting to newtonian representation.
/// </summary>
/// <remarks>
/// newton is the unit for force
/// joules is the unit for work done
/// by definition, work done = force X distance
/// so multiply newton by metre to get joules
/// 1 newton = 1 joule/meter
/// </remarks>
public class Force : UnitBase, IForce
{
public static Energies.Energy ToEnergy(Distances.IDistance d)
{
return new Energies.Energy(d.TotalMeters.ToDouble());
}
public static Energies.Energy ToEnergy(System.TimeSpan t) => ToEnergy(new Distances.Distance(t.TotalSeconds));
public static implicit operator double(Force t) { return t.Units.ToDouble(); }
public static implicit operator Force(double t) { return new Force(t); }
public const double Newton = 1D;
public const double ErgPreNewton = 10000000.00;
//0.0000001 Converts from erg
//10000000 Converts to erg
static readonly System.Collections.Generic.IList<string> ForceSymbols = new System.Collections.Generic.List<string>()
{
"N"
}.AsReadOnly();
/// <summary>
/// Constructs the default 1 newton = 1 joule/meter
/// </summary>
public Force()
: base(Newton)
{
}
/// <summary>
/// Constructs a newtonian <see cref="Force"/> with the given parameters
/// </summary>
/// <param name="value">The newtonian value which describes to the <see cref="TotalNewtons"/></param>
public Force(double value)
: base(Newton)
{
Units = value;
}
/// <summary>
/// Constructs a newtonian <see cref="Force"/> from another <see cref="Force"/>
/// </summary>
/// <param name="other">The other <see cref="Force"/></param>
public Force(Force other) : base(Newton, other) { }
/// <summary>
/// Constructs a newtonian <see cref="Force"/> from another <see cref="Force"/> with the specified parameters
/// </summary>
/// <param name="value">The newtonian value which describes to the <see cref="TotalNewtons"/></param>
/// <param name="other">The other <see cref="Force"/></param>
public Force(Number value, Force other) : base(Newton, other) { Units = value; }
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(ForceSymbols);
}
}
/// <summary>
/// joules
/// </summary>
public Energies.Energy TotalErg => new(Units * ErgPreNewton);
public virtual Number TotalNewtons
{
get { return Units; }
}
public static Force operator +(Force a, int amount)
{
return new Force(a.Units.ToDouble() + amount);
}
public static Force operator -(Force a, int amount)
{
return new Force(a.Units.ToDouble() - amount);
}
public static Force operator *(Force a, int amount)
{
return new Force(a.Units.ToDouble() * amount);
}
public static Force operator /(Force a, int amount)
{
return new Force(a.Units.ToDouble() / amount);
}
public static Force operator %(Force a, int amount)
{
return new Force(a.Units.ToDouble() % amount);
}
public static bool operator >(Force a, IForce b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalUnits;
return a.Units > b.TotalUnits;
}
public static bool operator <(Force a, IForce b)
{
return (a > b).Equals(false);
}
public static bool operator ==(Force a, IForce b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalUnits;
return a.Units == b.TotalUnits;
}
public static bool operator !=(Force a, IForce b)
{
return (a == b).Equals(false);
}
public override bool Equals(object obj)
{
if (obj is IForce) return ((IForce)obj) == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
}
}
/// <summary>
/// A class which is useful for dealing with the frequency and velocity of wave forms
/// </summary>
public static class Wavelengths
{
public interface IWavelength : IUnit
{
Distances.IDistance TotalMeters { get; }
Frequencies.IFrequency TotalHz { get; }
Energies.IEnergy TotalJoules { get; }
Velocities.IVelocity TotalVelocity { get; }
//Shape is Waveform
//ToWaveform(Shape)
}
/*
newton is the unit for Wavelength
joules is the unit for work done
by definition, work done = Wavelength X distance
so multiply newton by metre to get joules
1 newton = 1 joule/meter
*/
/// <summary>
/// A class which is useful for computing the frequency and velocity of waves from physical <see cref="Forces"/>
/// </summary>
public class Wavelength : UnitBase, IWavelength
{
public static implicit operator double(Wavelength t) { return t.Units.ToDouble(); }
public static implicit operator Wavelength(double t) { return new Wavelength(t); }
static readonly System.Collections.Generic.IList<string> WavelengthSymbols = new System.Collections.Generic.List<string>()
{
"nm",
"μm",
"m"
}.AsReadOnly();
public const double Nm = 1D;
public Wavelength()
: base(Nm)
{
}
public Wavelength(Distances.Distance meters)
: base(Nm)
{
Units = meters.TotalMeters * Distances.Distance.NanometersPerMeter;
}
public Wavelength(double nanometers)
: base(Nm)
{
Units = nanometers;
}
public Wavelength(Frequencies.Frequency hZ)
: base(Nm)
{
Units = Velocities.Velocity.MaxValue.Units.ToComplex() * hZ.TotalHertz.ToComplex();
}
public Wavelength(Wavelength other) : base(Nm, other) { }
public Wavelength(Number value, Wavelength other) : base(Nm, other) { Units = value; }
protected override System.Collections.Generic.List<string> m_Symbols
{
get
{
return new(WavelengthSymbols);
}
}
public virtual Distances.IDistance TotalMeters
{
get { return new Distances.Distance(Units.ToComplex() * Distances.Distance.NanometersPerMeter); }
}
public virtual Velocities.IVelocity TotalVelocity
{
get { return new Velocities.Velocity(Velocities.Velocity.MaxValue.Units.ToDouble() / Units.ToDouble()); }
}
public virtual Frequencies.IFrequency TotalHz
{
get { return new Frequencies.Frequency(TotalVelocity.TotalMetersPerSecond.ToDouble() * TotalMeters.TotalUnits.ToDouble()); }
}
public virtual Energies.IEnergy TotalJoules
{
get { return new Energies.Energy(new Number(Common.Physics.hc / TotalMeters.TotalUnits.ToDouble())); }
}
public static Wavelength operator +(Wavelength a, int amount)
{
return new Wavelength(a.Units.ToDouble() + amount);
}
public static Wavelength operator -(Wavelength a, int amount)
{
return new Wavelength(a.Units.ToDouble() - amount);
}
public static Wavelength operator *(Wavelength a, int amount)
{
return new Wavelength(a.Units.ToDouble() * amount);
}
public static Wavelength operator /(Wavelength a, int amount)
{
return new Wavelength(a.Units.ToDouble() / amount);
}
public static Wavelength operator %(Wavelength a, int amount)
{
return new Wavelength(a.Units.ToDouble() % amount);
}
public static bool operator >(Wavelength a, IWavelength b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant > b.TotalUnits;
return a.Units > b.TotalUnits;
}
public static bool operator <(Wavelength a, IWavelength b)
{
return !(a > b);
}
public static bool operator ==(Wavelength a, IWavelength b)
{
if (a.Constant.Equals(b.Constant).Equals(false))
return a.Units * b.Constant == b.TotalUnits;
return a.Units == b.TotalUnits;
}
public static bool operator !=(Wavelength a, IWavelength b)
{
return !(a == b);
}
public override bool Equals(object obj)
{
if (obj is IWavelength wavelength) return wavelength == this;
return base.Equals(obj);
}
public override int GetHashCode()
{
return Constant.GetHashCode() << 16 | Units.GetHashCode() >> 16;
}
}
/// <summary>
/// Represents a pointer
/// </summary>
public class NativeUnit : UnitBase
{
static readonly System.Collections.Generic.List<System.Type> ReferenceTypes = new()
{
typeof(int).MakeByRefType(),
typeof(nint).MakeByRefType(),
typeof(nuint).MakeByRefType(),
};
/// <summary>
/// Reference types are first
/// </summary>
static readonly System.Collections.Generic.List<string> NativeSymbols = new(System.Linq.Enumerable.Select(ReferenceTypes, rt => rt.Name))
{
typeof(nint).Name, typeof(nuint).Name, typeof(System.IntPtr).Name,
};
/// <summary>
/// <see cref="System.Linq.Enumerable.Reverse"/> of <see cref="NativeSymbols"/>
/// </summary>
protected override System.Collections.Generic.List<string> m_Symbols => System.Linq.Enumerable.ToList(System.Linq.Enumerable.Reverse(NativeSymbols));
public NativeUnit() : base(System.Runtime.CompilerServices.Unsafe.SizeOf<nuint>()) { }
public static implicit operator System.IntPtr(NativeUnit native) => (System.IntPtr)native.Value;
public static implicit operator nint(NativeUnit native) => (nint)native.Value;
public static implicit operator nuint(NativeUnit native) => (nuint)native.Value;
}
}
//TODO
//Current -> //http://en.wikipedia.org/wiki/Coulomb
//Charge
//Degree
//Radian
//ArcSecond
})
let me know what you think and I will see about making an update to my code on Github when possible.