/PhysMeasure/PhysicalMeasure/PhysicalMeasure.2.Classes.cs
C# | 7916 lines | 6243 code | 1331 blank | 342 comment | 1447 complexity | 6d0760784ae4e865085f2ea494146e65 MD5 | raw file
Large files files are truncated, but you can click here to view the full file
- /* http://physicalmeasure.codeplex.com */
- /* http://en.wikipedia.org/wiki/International_System_of_Units */
- /* http://en.wikipedia.org/wiki/Physical_quantity */
- /* http://en.wikipedia.org/wiki/Physical_constant */
-
- using System;
- using System.Collections.Generic;
- using System.Linq;
- using System.Diagnostics;
- using System.Globalization;
- using System.Runtime.Serialization;
-
- using static PhysicalMeasure.DimensionExponentsExtension;
-
- namespace PhysicalMeasure
- {
- #region Physical Measure Classes
-
- #region Physical Measure Exceptions
-
- [Serializable]
- public class PhysicalUnitFormatException : FormatException
- {
- public PhysicalUnitFormatException(String message, Exception innerException)
- : base(message, innerException)
- {
- }
-
- protected PhysicalUnitFormatException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
- public PhysicalUnitFormatException()
- : this("The string argument is not in a valid physical unit format.")
- {
- }
-
- public PhysicalUnitFormatException(String message)
- : base(message)
- {
- }
- }
-
- [Serializable]
- public class PhysicalUnitMathException : Exception
- {
- public PhysicalUnitMathException(String message, Exception innerException)
- : base(message, innerException)
- {
- }
-
- protected PhysicalUnitMathException(SerializationInfo info, StreamingContext context)
- : base(info, context)
- {
- }
-
- public PhysicalUnitMathException()
- : this("The result of the math operation on the Unit argument can't be represented by this implementation of PhysicalMeasure.")
- {
- }
-
- public PhysicalUnitMathException(String message)
- : base(message)
- {
- }
- }
-
- #endregion Physical Measure Exceptions
-
- #region Dimension Exponents Classes
-
- public class DimensionExponents : IEquatable<DimensionExponents>
- {
-
- private SByte[] exponents;
-
- public DimensionExponents(SByte[] exponents)
- {
- this.exponents = exponents;
- }
-
- public override int GetHashCode()
- {
- if (exponents == null)
- {
- return base.GetHashCode();
- }
- return exponents.GetHashCode();
- }
-
- public override Boolean Equals(Object obj)
- {
- if (obj == null)
- return false;
-
- DimensionExponents DimensionExponentsObj = obj as DimensionExponents;
- if (DimensionExponentsObj == null)
- return false;
- else
- return Equals(DimensionExponentsObj);
- }
-
- public Boolean Equals(DimensionExponents other)
- {
- if (other == null)
- return false;
-
- return Equals(this.exponents, other.exponents);
- }
-
- }
-
- public static class DimensionExponentsExtension
- {
- public static Boolean DimensionEquals(this SByte[] exponents1, SByte[] exponents2)
- {
- Debug.Assert(exponents1 != null, "Parameter must be specified");
- Debug.Assert(exponents2 != null, "Parameter must be specified");
-
- if (ReferenceEquals(exponents1, exponents2))
- {
- return true;
- }
-
- SByte MinNoOfBaseUnits = (SByte)Math.Min(exponents1.Length, exponents2.Length);
- SByte MaxNoOfBaseUnits = (SByte)Math.Max(exponents1.Length, exponents2.Length);
-
- Debug.Assert(MaxNoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + MaxNoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
-
- Boolean equal = true;
- SByte i = 0;
-
- do
- { // Compare exponents where defined in both arrays
- equal = exponents1[i] == exponents2[i];
- i++;
- }
- while (equal && i < MinNoOfBaseUnits);
-
- // Check tail of longest array to contain only zeros
- while (equal && i < MaxNoOfBaseUnits)
- {
- if (exponents1.Length > exponents2.Length)
- {
- equal = exponents1[i] == 0;
- }
- else
- {
- equal = exponents2[i] == 0;
- }
- i++;
- }
- return equal;
- }
-
- public static Boolean IsDimensionless(this SByte[] exponents)
- {
- Debug.Assert(exponents != null, "Parameter needed");
-
- SByte NoOfBaseUnits = (SByte)exponents.Length;
- Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
-
- Boolean isDimensionless = true;
- SByte i = 0;
- do
- {
- isDimensionless = exponents[i] == 0;
- i++;
- }
- while (i < NoOfBaseUnits && isDimensionless);
-
- return isDimensionless;
- }
-
- public static SByte NoOfDimensions(this SByte[] exponents)
- {
- Debug.Assert(exponents != null, "Parameter needed");
-
- SByte NoOfBaseUnits = (SByte)exponents.Length;
- Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
-
- SByte noOfDimensions = 0;
- SByte i = 0;
- do
- {
- if (exponents[i] != 0)
- {
- noOfDimensions++;
- }
- i++;
- }
- while (i < NoOfBaseUnits);
-
- return noOfDimensions;
- }
-
- public delegate SByte CombineExponentsFunc(SByte e1, SByte e2);
-
- public static SByte SByte_Mult(SByte e1, SByte e2) => (SByte)(e1 * e2);
- public static SByte SByte_Div(SByte e1, SByte e2) => (SByte)(e1 / e2);
-
- public static SByte SByte_Add(SByte e1, SByte e2) => (SByte)(e1 + e2);
- public static SByte SByte_Sub(SByte e1, SByte e2) => (SByte)(e1 - e2);
-
-
- public static SByte[] CombineExponentArrays(this SByte[] exponents1, SByte[] exponents2, CombineExponentsFunc cef)
- {
- Debug.Assert(exponents1 != null, "Parameter exponents1 needed");
- Debug.Assert(exponents2 != null, "Parameter exponents2 needed");
-
- SByte NoOfBaseUnits1 = (SByte)exponents1.Length;
- SByte NoOfBaseUnits2 = (SByte)exponents2.Length;
- SByte MaxNoOfBaseUnits = (SByte)Math.Max(NoOfBaseUnits1, NoOfBaseUnits2);
- SByte MinNoOfBaseUnits = (SByte)Math.Min(NoOfBaseUnits1, NoOfBaseUnits2);
-
- Debug.Assert(NoOfBaseUnits1 <= Physics.NoOfBaseQuanties + 1, "exponents1 has too many base units:" + NoOfBaseUnits1.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
- Debug.Assert(NoOfBaseUnits2 <= Physics.NoOfBaseQuanties + 1, "exponents2 has too many base units:" + NoOfBaseUnits2.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
-
- SByte[] NewExponents = new SByte[MaxNoOfBaseUnits];
- SByte i = 0;
-
- do
- {
- NewExponents[i] = cef(exponents1[i], exponents2[i]);
- i++;
- }
- while (i < MinNoOfBaseUnits);
-
- while (i < MaxNoOfBaseUnits)
- {
- if (NoOfBaseUnits1 > NoOfBaseUnits2)
- {
- NewExponents[i] = exponents1[i];
- }
- else
- {
- NewExponents[i] = cef(0, exponents2[i]);
- }
-
- i++;
- }
-
- return NewExponents;
- }
- public static SByte[] Multiply(this SByte[] exponents1, SByte[] exponents2)
- {
- SByte[] NewExponents = CombineExponentArrays(exponents1, exponents2, SByte_Add);
- return NewExponents;
- }
-
- public static SByte[] Divide(this SByte[] exponents1, SByte[] exponents2)
- {
- SByte[] NewExponents = CombineExponentArrays(exponents1, exponents2, SByte_Sub);
- return NewExponents;
- }
-
- public static SByte[] Power(this SByte[] exponents, SByte exponent)
- {
- Debug.Assert(exponents != null, "Parameter needed");
- Debug.Assert(exponent != 0, "Parameter needed");
-
- SByte NoOfBaseUnits = (SByte)exponents.Length;
- Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
-
- SByte[] NewExponents = new SByte[NoOfBaseUnits];
- SByte i = 0;
- do
- {
- NewExponents[i] = (SByte)(exponents[i] * exponent);
-
- i++;
- }
- while (i < NoOfBaseUnits);
-
- return NewExponents;
- }
-
- public static SByte[] Root(this SByte[] exponents, SByte exponent)
- {
- Debug.Assert(exponents != null, "Parameter needed");
- Debug.Assert(exponent != 0, "Parameter needed");
-
- SByte NoOfBaseUnits = (SByte)exponents.Length;
- Debug.Assert(NoOfBaseUnits <= Physics.NoOfBaseQuanties + 1, "Too many base units:" + NoOfBaseUnits.ToString() + ". No more than " + (Physics.NoOfBaseQuanties + 1) + " expected.");
-
- SByte[] NewExponents = new SByte[NoOfBaseUnits];
- SByte i = 0;
- Boolean OK = true;
- do
- {
- int Remainder;
- int NewExponent = Math.DivRem(exponents[i], exponent, out Remainder);
- OK = Remainder == 0;
- NewExponents[i] = (SByte)NewExponent;
-
- i++;
- }
- while (i < NoOfBaseUnits && OK);
-
- if (!OK)
- {
- Debug.Assert(OK, "Verify to not happening");
-
- //if (ThrowExceptionOnUnitMathError) {
- throw new PhysicalUnitMathException("The result of the math operation on the Unit argument can't be represented by this implementation of PhysicalMeasure: (" + exponents.ToString() + ").Root(" + exponent.ToString() + ")");
- //}
- //NewExponents = null;
- }
- return NewExponents;
- }
-
-
- public static SByte[] AllExponents(this SByte[] Exponents, SByte length)
- {
- SByte[] resExponents;
- if (Exponents.Length < length)
- {
- resExponents = new SByte[length];
- foreach (int i in Enumerable.Range(0, length))
- {
- resExponents[i] = Exponents[i];
- }
- }
- else
- {
- Debug.Assert(Exponents.Length == length);
- resExponents = Exponents;
- }
-
- return resExponents;
- }
-
- public static String ArrayToString(this SByte[] exponents)
- {
- String str = "[";
-
- foreach (int i in Enumerable.Range(0, exponents.Length))
- {
- if (i > 0)
- {
- str = str + ", ";
- }
- str = str + exponents[i].ToString();
- }
- str = str + "]";
-
- return str;
- }
- }
- #endregion Dimension Exponents Classes
-
- public class NamedObject : INamed
- {
- private readonly String name;
- public String Name => name;
-
- public NamedObject(String someName)
- {
- this.name = someName;
- }
-
- public override String ToString() => Name;
- }
-
- #region Physical Unit prefix Classes
-
- public class UnitPrefixExponent : IUnitPrefixExponent
- {
- private SByte exponent;
-
- public SByte Exponent => exponent;
- public Double Value => Math.Pow(10, exponent);
-
- public UnitPrefixExponent(SByte somePrefixExponent)
- {
- this.exponent = somePrefixExponent;
- }
-
- #region IUnitPrefixExponentMath implementation
- public IUnitPrefixExponent Multiply(IUnitPrefixExponent prefix) => new UnitPrefixExponent((SByte)(this.exponent + prefix.Exponent));
-
- public IUnitPrefixExponent Divide(IUnitPrefixExponent prefix) => new UnitPrefixExponent((SByte)(this.exponent - prefix.Exponent));
-
- public IUnitPrefixExponent Power(SByte someExponent) => new UnitPrefixExponent((SByte)(this.exponent * someExponent));
-
- public IUnitPrefixExponent Root(SByte someExponent)
- {
- SByte result_exponent = (SByte)(this.exponent / someExponent);
- Debug.Assert(result_exponent * someExponent == this.exponent, " Root result exponent must be an integer");
- return new UnitPrefixExponent(result_exponent);
- }
-
- #endregion IUnitPrefixExponentMath implementation
-
- public override String ToString() => Exponent.ToString();
- }
-
- public class UnitPrefix : NamedObject, IUnitPrefix
- {
- private IUnitPrefixTable unitPrefixTable;
- private Char prefixChar;
- IUnitPrefixExponent prefixExponent;
-
- #region IUnitPrefix implementation
-
- public Char PrefixChar => prefixChar;
-
- public SByte Exponent => prefixExponent.Exponent;
-
- public Double Value => prefixExponent.Value;
-
- #endregion IUnitPrefix implementation
-
- public UnitPrefix(IUnitPrefixTable someUnitPrefixTable, String someName, Char somePrefixChar, IUnitPrefixExponent somePrefixExponent)
- : base(someName)
- {
- this.unitPrefixTable = someUnitPrefixTable;
- this.prefixChar = somePrefixChar;
- this.prefixExponent = somePrefixExponent;
- }
-
- public UnitPrefix(IUnitPrefixTable someUnitPrefixTable, String someName, Char somePrefixChar, SByte somePrefixExponent)
- : this(someUnitPrefixTable, someName, somePrefixChar, new UnitPrefixExponent(somePrefixExponent))
- {
- }
-
- public IUnitPrefix Multiply(IUnitPrefix prefix)
- {
- IUnitPrefix unitPrefix = null;
- IUnitPrefixExponent resultExponent = this.prefixExponent.Multiply(prefix);
- if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
- {
- unitPrefix = new UnitPrefix(null, null, '\0', resultExponent);
- }
- return unitPrefix;
- }
-
- public IUnitPrefix Divide(IUnitPrefix prefix)
- {
- IUnitPrefix unitPrefix = null;
- IUnitPrefixExponent resultExponent = this.prefixExponent.Divide(prefix);
- if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
- {
- unitPrefix = new UnitPrefix(null, null, '\0', resultExponent);
- }
- return unitPrefix;
- }
-
-
- #region IUnitPrefixExponentMath implementation
- public IUnitPrefixExponent Multiply(IUnitPrefixExponent prefix)
- {
- IUnitPrefix unitPrefix = null;
- IUnitPrefixExponent resultExponent = this.prefixExponent.Multiply(prefix);
- if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
- {
- return resultExponent;
- }
- return unitPrefix;
- }
-
- public IUnitPrefixExponent Divide(IUnitPrefixExponent prefix)
- {
- IUnitPrefix unitPrefix = null;
- IUnitPrefixExponent resultExponent = this.prefixExponent.Divide(prefix);
- if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
- {
- return resultExponent;
- }
- return unitPrefix;
- }
-
- public IUnitPrefixExponent Power(SByte someExponent)
- {
- IUnitPrefix unitPrefix = null;
- IUnitPrefixExponent resultExponent = this.prefixExponent.Power(someExponent);
- if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
- {
- return resultExponent;
- }
- return unitPrefix;
- }
-
- public IUnitPrefixExponent Root(SByte someExponent)
- {
- IUnitPrefix unitPrefix = null;
- IUnitPrefixExponent resultExponent = this.prefixExponent.Root(someExponent);
- if (!unitPrefixTable.GetUnitPrefixFromExponent(resultExponent, out unitPrefix))
- {
- return resultExponent;
- }
- return unitPrefix;
- }
-
- public IPrefixedUnit Multiply(INamedSymbolUnit symbolUnit) => new PrefixedUnit(this, symbolUnit);
-
-
- #endregion IUnitPrefixExponentMath implementation
-
- public override String ToString() => PrefixChar.ToString();
- }
-
- public class UnitPrefixTable : IUnitPrefixTable
- {
- private readonly UnitPrefix[] unitPrefixes;
-
- public UnitPrefix[] UnitPrefixes => unitPrefixes;
-
- public UnitPrefixTable(UnitPrefix[] someUnitPrefix)
- {
- this.unitPrefixes = someUnitPrefix;
- }
-
- public Boolean GetUnitPrefixFromExponent(IUnitPrefixExponent someExponent, out IUnitPrefix unitPrefix)
- {
- Debug.Assert(someExponent.Exponent != 0);
-
- IUnitPrefix TempUnitPrefix;
- SByte ScaleFactorExponent;
-
- GetFloorUnitPrefixAndScaleFactorFromExponent(someExponent.Exponent, out TempUnitPrefix, out ScaleFactorExponent);
-
- if (ScaleFactorExponent == 0)
- {
- unitPrefix = TempUnitPrefix;
- return true;
- }
- else
- {
- unitPrefix = null;
- return false;
- }
- }
-
- public void GetFloorUnitPrefixAndScaleFactorFromExponent(SByte someExponent, out IUnitPrefix unitPrefix, out SByte ScaleFactorExponent)
- {
- Debug.Assert(someExponent != 0);
-
- int UnitPrefix = 11; // 10^1
- while (UnitPrefix - 1 >= 0 && UnitPrefixes[UnitPrefix - 1].Exponent <= someExponent)
- {
- UnitPrefix--;
- }
- while (UnitPrefix + 1 < UnitPrefixes.Length && UnitPrefixes[UnitPrefix + 1].Exponent >= someExponent)
- {
- UnitPrefix++;
- }
- unitPrefix = UnitPrefixes[UnitPrefix];
- ScaleFactorExponent = (SByte)(someExponent - unitPrefix.Exponent);
- }
-
- public Boolean GetPrefixCharFromExponent(IUnitPrefixExponent someExponent, out Char prefixChar)
- {
- prefixChar = '\0';
- foreach (UnitPrefix us in UnitPrefixes)
- {
- if (us.Exponent == someExponent.Exponent)
- {
- prefixChar = us.PrefixChar;
- return true;
- }
- }
- return false;
- }
-
- public Boolean GetUnitPrefixFromPrefixChar(Char somePrefixChar, out IUnitPrefix unitPrefix)
- {
- switch (somePrefixChar)
- {
- case '\x03BC':
-
- // 'μ' // '\0x03BC' (char)956
- // 'µ' // '\0x00B5' (char)181
- somePrefixChar = 'µ'; // 'µ' MICRO SIGN '\0x00B5' (char)181
- break;
- case 'k':
- somePrefixChar = 'K'; // Kilo
- break;
- case 'h':
- somePrefixChar = 'H'; // Hecto
- break;
- }
-
- foreach (UnitPrefix up in UnitPrefixes)
- {
- if (up.PrefixChar == somePrefixChar)
- {
- unitPrefix = up;
- return true;
- }
- }
- unitPrefix = null;
- return false;
- }
-
- public Boolean GetExponentFromPrefixChar(Char somePrefixChar, out IUnitPrefixExponent exponent)
- {
- switch (somePrefixChar)
- {
- case '\x03BC':
-
- // 'μ' // '\0x03BC' (Char)956
- // 'µ' // '\0x00B5' (Char)181
- somePrefixChar = 'µ'; // 'µ' MICRO SIGN '\0x00B5' (Char)181
- break;
- case 'k':
- somePrefixChar = 'K'; // Kilo
- break;
- case 'h':
- somePrefixChar = 'H'; // Hecto
- break;
- }
-
- foreach (UnitPrefix up in UnitPrefixes)
- {
- if (up.PrefixChar == somePrefixChar)
- {
- exponent = up;
- return true;
- }
- }
- exponent = null;
- return false;
- }
-
-
- public IUnitPrefix UnitPrefixFromPrefixChar(char somePrefixChar)
- {
- IUnitPrefix unitPrefix = null;
- GetUnitPrefixFromPrefixChar(somePrefixChar, out unitPrefix);
- return unitPrefix;
- }
-
- public IUnitPrefixExponent ExponentFromPrefixChar(char somePrefixChar)
- {
- IUnitPrefixExponent exponent = null;
- GetExponentFromPrefixChar(somePrefixChar, out exponent);
- return exponent;
- }
-
- public IUnitPrefix this[char somePrefixChar] => UnitPrefixFromPrefixChar(somePrefixChar);
- }
-
- #endregion Physical Unit prefix Classes
-
- #region Value Conversion Classes
-
- public abstract class ValueConversion : IValueConversion
- {
- // Specific/absolute quantity unit conversion (e.g. specific temperature)
- // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
- public Double Convert(Double value, Boolean backwards = false)
- {
- if (backwards)
- {
- return ConvertToPrimaryUnit(value);
- }
- else
- {
- return ConvertFromPrimaryUnit(value);
- }
- }
-
- public abstract Double ConvertFromPrimaryUnit(Double value);
- public abstract Double ConvertToPrimaryUnit(Double value);
-
- // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
- public Double Convert(Boolean backwards = false)
- {
- if (backwards)
- {
- return ConvertToPrimaryUnit();
- }
- else
- {
- return ConvertFromPrimaryUnit();
- }
- }
-
- public abstract Double ConvertFromPrimaryUnit();
- public abstract Double ConvertToPrimaryUnit();
-
- public abstract Double LinearOffset { get; }
- public abstract Double LinearScale { get; }
- }
-
- public class LinearValueConversion : ValueConversion
- {
- private Double offset;
- private Double scale;
-
- public Double Offset
- {
- get { return offset; }
- set { offset = value; }
- }
-
- public Double Scale
- {
- get { return scale; }
- set { scale = value; }
- }
-
- public override Double LinearOffset => offset;
-
- public override Double LinearScale => scale;
-
- public LinearValueConversion(Double someOffset, Double someScale)
- {
- this.Offset = someOffset;
- this.Scale = someScale;
- }
-
- // Specific/absolute quantity unit conversion (e.g. specific temperature)
- // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
- public override Double ConvertFromPrimaryUnit(Double value) => (value * this.Scale) + this.Offset;
-
- public override Double ConvertToPrimaryUnit(Double value)
- {
- Double convertedValue = (value - this.Offset) / this.Scale;
- return convertedValue;
- }
-
- // Unspecific/relative non-quantity unit conversion (e.g. temperature interval)
- // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
- public override Double ConvertFromPrimaryUnit() => 1.0d * this.Scale;
-
- public override Double ConvertToPrimaryUnit() => 1.0d / this.Scale;
- }
-
- public class ScaledValueConversion : LinearValueConversion
- {
- public ScaledValueConversion(Double someScale)
- : base(0, someScale)
- {
- Debug.Assert(someScale != 0, "Parameter needed");
- Debug.Assert(!Double.IsInfinity(someScale), "Finite scale value needed");
-
- if (someScale == 0)
- {
- throw new ArgumentException("0 is not a valid scale", nameof(someScale));
- }
- if (Double.IsInfinity(someScale))
- {
- throw new ArgumentException("Infinity is not a valid scale", nameof(someScale));
- }
- }
- }
-
- public class IdentityValueConversion : ScaledValueConversion
- {
- public IdentityValueConversion()
- : base(1)
- {
- }
- }
-
- public class CombinedValueConversion : ValueConversion
- {
- private IValueConversion firstValueConversion;
- private IValueConversion secondValueConversion;
-
- private Boolean firstValueConversionDirectionInverted;
- private Boolean secondValueConversionDirectionInverted;
-
- public override Double LinearOffset => firstValueConversion.LinearOffset + secondValueConversion.LinearOffset;
-
- public override Double LinearScale => firstValueConversion.LinearScale * secondValueConversion.LinearScale;
-
-
- public CombinedValueConversion(IValueConversion firstValueConversion, Boolean firstValueConversionDirectionInverted, IValueConversion secondValueConversion, Boolean secondValueConversionDirectionInverted)
- {
- this.firstValueConversion = firstValueConversion;
- this.firstValueConversionDirectionInverted = firstValueConversionDirectionInverted;
- this.secondValueConversion = secondValueConversion;
- this.secondValueConversionDirectionInverted = secondValueConversionDirectionInverted;
- }
-
- // Specific/absolute quantity unit conversion (e.g. specific temperature)
- // Conversion value is specified. Must assume Specific conversion e.g. specific temperature.
-
- public override Double ConvertFromPrimaryUnit(Double value) => this.secondValueConversion.Convert(this.firstValueConversion.Convert(value, this.firstValueConversionDirectionInverted), this.secondValueConversionDirectionInverted);
-
- public override Double ConvertToPrimaryUnit(Double value) => this.firstValueConversion.Convert(this.secondValueConversion.Convert(value, !this.secondValueConversionDirectionInverted), !this.firstValueConversionDirectionInverted);
-
- // Unspecific/relative non-quantity unit conversion (e.g. temperature interval)
- // No Conversion value is specified. Must assume relative conversion e.g. temperature interval.
-
- public override Double ConvertFromPrimaryUnit() => this.secondValueConversion.Convert(this.firstValueConversion.Convert(this.firstValueConversionDirectionInverted), this.secondValueConversionDirectionInverted);
-
- public override Double ConvertToPrimaryUnit() => this.firstValueConversion.Convert(this.secondValueConversion.Convert(!this.secondValueConversionDirectionInverted), !this.firstValueConversionDirectionInverted);
- }
-
- #endregion Value Conversion Classes
-
- #region Physical Unit Classes
-
- public class NamedSymbol : NamedObject, INamedSymbol
- {
- private String symbol;
- public String Symbol { get { return symbol; } set { symbol = value; } }
-
- public NamedSymbol(String someName, String someSymbol)
- : base(someName)
- {
- this.Symbol = someSymbol;
- }
- }
-
- public abstract class Unit : ISystemItem, IUnit /* <BaseUnit | DerivedUnit | ConvertibleUnit | CombinedUnit> */
- {
- protected Unit()
- {
- }
-
- public static IUnit MakePhysicalUnit(SByte[] exponents, Double ConversionFactor = 1, Double ConversionOffset = 0)
- {
- return MakePhysicalUnit(Physics.SI_Units, exponents, ConversionFactor, ConversionOffset);
- }
-
- public static Unit MakePhysicalUnit(IUnitSystem system, SByte[] exponents, Double ConversionFactor = 1, Double ConversionOffset = 0)
- {
- Unit res_unit = null;
- int nod = exponents.NoOfDimensions();
- if (nod == 0)
- {
- res_unit = Physics.dimensionless;
- }
- else
- {
- res_unit = system.UnitFromExponents(exponents);
- }
- if (ConversionFactor != 1 || ConversionOffset != 0)
- {
- if (ConversionOffset == 0)
- {
- res_unit = new ConvertibleUnit(null, res_unit, new ScaledValueConversion(ConversionFactor));
- }
- else
- {
- res_unit = new ConvertibleUnit(null, res_unit, new LinearValueConversion(ConversionOffset, ConversionFactor));
- }
- }
-
- Debug.Assert(res_unit != null, "res_unit must be found");
- return res_unit;
- }
-
- public PrefixedUnitExponentList AsPrefixedUnitExponentList()
- {
- IUnitSystem us = this.ExponentsSystem;
- PrefixedUnitExponentList res = new PrefixedUnitExponentList(this.Exponents.Select((exp, i) =>
- {
- if (exp != 0)
- {
- return new PrefixedUnitExponent(us.BaseUnits[i], exp);
- }
- else
- {
- return null;
- }
- }));
- return res;
- }
-
- #if DEBUG
- // [Conditional("DEBUG")]
- public void TestPropertiesPrint()
- {
- Boolean test = true;
- if (test)
- {
- string KindStr = this.Kind.ToString();
- string SimpleSystemStr = SimpleSystem?.ToString();
- string ExponentsSystemStr = ExponentsSystem?.ToString();
- string ExponentsStr = Exponents?.ArrayToString();
-
- string DimensionlessStr = Dimensionless?.ToPrintString();
- string IsDimensionlessStr = IsDimensionless.ToString();
-
- string ThisPrintStr = this.ToPrintString();
- string ThisStr = this.ToString();
- }
- }
- #endif // DEBUG
-
- public abstract IUnitSystem SimpleSystem { get; set; }
- public abstract IUnitSystem ExponentsSystem { get; }
-
- public abstract UnitKind Kind { get; }
- public abstract SByte[] Exponents { get; }
-
-
- public virtual Unit Dimensionless => Physics.dimensionless;
- public virtual Boolean IsDimensionless
- {
- get
- {
- SByte[] exponents = Exponents;
- if (Exponents == null)
- {
- Debug.Assert(Exponents != null, "Exponents must be found");
- return false; // Maybe combined unit with Assume
- }
- return Exponents.IsDimensionless();
- }
- }
-
- public override int GetHashCode() => this.ExponentsSystem.GetHashCode() + this.Exponents.GetHashCode();
-
- #region Unit Expression parser methods
- /**
- U = U "*" F | U F | U "/" F | F .
- F = SUX | "(" U ")" .
- SUX = U | S U | U X | S U X .
-
- U = F Uopt .
- //Uopt = "*" F Uopt | "/" F Uopt | UX | e .
- Uopt = "*" F Uopt | "/" F Uopt| U | e .
- F = SUX | "(" U ")" .
- SUX = SU Xopt .
- SU = Sopt u .
- Sopt = s | e .
- Xopt = x | e .
-
- * s : scale prefix char
- * u : unit symbol
- * x : exponent number
- **/
-
- #region IPhysicalUnit unit expression parser methods
-
- /// <summary>
- /// Parses the physical quantity from a string in form
- /// [prefix] [unitSymbol]
- /// </summary>
- public static Unit Parse(String unitString)
- {
- Unit pu = null;
- String resultLine = null;
- pu = ParseUnit(ref unitString, ref resultLine, throwExceptionOnInvalidInput: true);
- return pu;
- }
-
- public static Unit ParseUnit(ref String unitString, ref String resultLine, Boolean throwExceptionOnInvalidInput = true)
- {
- Unit pu = null;
-
- Char timeSeparator = ':';
- Char[] separators = { timeSeparator };
-
- Char fractionUnitSeparator = '\0';
- String fractionUnitSeparatorStr = null;
-
- int unitStrCount = 0;
- int unitStrStartCharIndex = 0;
- int nextUnitStrStartCharIndex = 0;
- Boolean validFractionalUnit = true;
- int lastUnitFieldRemainingLen = 0;
-
- Stack<Tuple<string, Unit>> FractionalUnits = new Stack<Tuple<string, Unit>>();
-
- while (validFractionalUnit && (unitStrStartCharIndex >= 0) && (unitStrStartCharIndex < unitString.Length))
- {
- int unitStrLen;
-
- int unitStrSeparatorCharIndex = unitString.IndexOfAny(separators, unitStrStartCharIndex);
- if (unitStrSeparatorCharIndex == -1)
- {
- unitStrLen = unitString.Length - unitStrStartCharIndex;
-
- nextUnitStrStartCharIndex = unitString.Length;
- }
- else
- {
- unitStrLen = unitStrSeparatorCharIndex - unitStrStartCharIndex;
-
- nextUnitStrStartCharIndex = unitStrSeparatorCharIndex + 1;
- }
-
- if (unitStrLen > 0)
- {
- unitStrCount++;
- string unitFieldString = unitString.Substring(unitStrStartCharIndex, unitStrLen).Trim();
-
- Unit tempPU = ParseUnit(null, ref unitFieldString);
-
- if (tempPU == null)
- {
- validFractionalUnit = false;
- resultLine = "'" + unitFieldString + "' is not a valid unit.";
- if (throwExceptionOnInvalidInput)
- {
- throw new PhysicalUnitFormatException("The string argument unitString is not in a valid physical unit format. " + resultLine);
- }
- }
- else
- {
- fractionUnitSeparatorStr = fractionUnitSeparator.ToString();
- FractionalUnits.Push(new Tuple<string, Unit>(fractionUnitSeparatorStr, tempPU));
-
- lastUnitFieldRemainingLen = unitFieldString.Length;
- if (lastUnitFieldRemainingLen != 0)
- { // Unparsed chars in (last?) field
- unitStrLen -= lastUnitFieldRemainingLen;
- }
- }
- }
-
- // Shift to next field
- if (unitStrSeparatorCharIndex >= 0)
- {
- fractionUnitSeparator = unitString[unitStrSeparatorCharIndex];
- }
- unitStrStartCharIndex = nextUnitStrStartCharIndex;
- }
-
- unitString = unitString.Substring(nextUnitStrStartCharIndex - lastUnitFieldRemainingLen);
-
- foreach (Tuple<string, Unit> tempFU in FractionalUnits)
- {
- Unit tempPU = tempFU.Item2;
- String tempFractionUnitSeparator = tempFU.Item1;
- if (pu == null)
- {
- pu = tempPU;
- fractionUnitSeparatorStr = tempFractionUnitSeparator;
- }
- else
- {
- if (new Quantity(tempPU).ConvertTo(pu) != null)
- {
- Debug.Assert(fractionUnitSeparatorStr != null, "Unit separator needed");
- pu = new MixedUnit(tempPU, fractionUnitSeparatorStr, pu);
-
- fractionUnitSeparatorStr = tempFractionUnitSeparator;
- }
- else
- {
- Debug.Assert(resultLine == null, "No resultLine expected");
- resultLine = tempPU.ToPrintString() + " is not a valid fractional unit for " + pu.ToPrintString() + ".";
-
- if (throwExceptionOnInvalidInput)
- {
- throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. " + resultLine);
- }
- }
- }
- }
- return pu;
- }
-
- // Token kind enum values
- public enum TokenKind
- {
- None = 0,
- Unit = 1,
- Exponent = 2,
- Operator = 3
- }
-
- // Operator kind enum values
- // Precedence for a group of operators is same as first (lowest) enum in the group
- public enum OperatorKind
- {
- None = 0,
-
- // Precedence == 2
- Mult = 2,
- Div = 3,
-
- //Precedence == 4
- Pow = 4,
- Root = 5
- }
-
- private static OperatorKind OperatorPrecedence(OperatorKind operatoren)
- {
- OperatorKind precedence = (OperatorKind)((int)operatoren & 0XE);
- return precedence;
- }
-
- private class Token
- {
- public readonly TokenKind TokenKind;
-
- public readonly Unit PhysicalUnit;
- public readonly SByte Exponent;
- public readonly OperatorKind Operator;
-
- public Token(Unit physicalUni)
- {
- this.TokenKind = TokenKind.Unit;
- this.PhysicalUnit = physicalUni;
- }
-
- public Token(SByte exponent)
- {
- this.TokenKind = TokenKind.Exponent;
- this.Exponent = exponent;
- }
-
- public Token(OperatorKind Operator)
- {
- this.TokenKind = TokenKind.Operator;
- this.Operator = Operator;
- }
- }
-
- private class ExpressionTokenizer
- {
- private String inputString;
- private int pos = 0;
- private int afterLastOperandPos = 0;
- private int lastValidPos = 0;
- private Boolean inputRecognized = true;
- private IUnit dimensionless = Physics.dimensionless;
- private Boolean throwExceptionOnInvalidInput = false;
-
- private Stack<OperatorKind> operators = new Stack<OperatorKind>();
- private List<Token> tokens = new List<Token>();
-
- private TokenKind lastReadToken = TokenKind.None;
-
- public ExpressionTokenizer(String inputStr)
- {
- this.inputString = inputStr;
- }
-
- public ExpressionTokenizer(IUnit someDimensionless, String someInputStr)
- {
- this.dimensionless = someDimensionless;
- this.inputString = someInputStr;
- }
-
- public ExpressionTokenizer(IUnit someDimensionless, Boolean someThrowExceptionOnInvalidInput, String someInputStr)
- {
- this.dimensionless = someDimensionless;
- this.throwExceptionOnInvalidInput = someThrowExceptionOnInvalidInput;
- this.inputString = someInputStr;
- }
-
- public string GetRemainingInput() => inputString.Substring(pos);
-
- public string GetRemainingInputForLastValidPos() => inputString.Substring(lastValidPos);
-
- public void SetValidPos()
- {
- if (operators.Count <= 1 && tokens.Count == 0)
- {
- lastValidPos = afterLastOperandPos;
- }
- }
-
- private Boolean PushNewOperator(OperatorKind newOperator)
- {
- if (lastReadToken != TokenKind.Operator)
- {
- if (operators.Count > 0)
- {
- // Pop operators with precedence higher than new operator
- OperatorKind precedence = OperatorPrecedence(newOperator);
- while ((operators.Count > 0) && (operators.Peek() >= precedence))
- {
- tokens.Add(new Token(operators.Pop()));
- }
- }
- operators.Push(newOperator);
- lastReadToken = TokenKind.Operator;
-
- return true;
- }
- else
- {
- if (throwExceptionOnInvalidInput)
- {
- throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. Invalid or missing unit at position " + pos.ToString());
- }
-
- return false;
- }
- }
-
- private void HandleNewOperator(OperatorKind newOperator)
- { // Push newOperator and shift Pos or mark as failed
- if (PushNewOperator(newOperator))
- {
- pos++;
- }
- else
- {
- inputRecognized = false;
- }
- }
-
- private Token RemoveFirstToken()
- { // return first operator from post fix operators
- Token token = tokens[0];
- tokens.RemoveAt(0);
-
- return token;
- }
-
- public Token GetToken()
- {
- Debug.Assert(inputString != null, "Source needed");
-
- if (tokens.Count > 0)
- { // return first operator from post fix operators
- return RemoveFirstToken();
- }
- int OperatorsCountForRecognizedTokens = operators.Count;
- while ((inputString.Length > pos) && inputRecognized)
- {
- Char c = inputString[pos];
- if (Char.IsWhiteSpace(c))
- {
- // Ignore spaces, tabs, etc.
- pos++;
- }
- else if (c == '*'
- || c == '·') // center dot '\0x0B7' (char)183 U+00B7
- {
- HandleNewOperator(OperatorKind.Mult);
- }
- else if (c == '/')
- {
- HandleNewOperator(OperatorKind.Div);
- }
- else if (c == '^')
- {
- HandleNewOperator(OperatorKind.Pow);
- }
- else if (c == '-'
- || c == '+'
- || Char.IsDigit(c))
- {
- // An exponent
- if ((lastReadToken != TokenKind.Unit) // Exponent can follow unit directly
- && ((lastReadToken != TokenKind.Operator) // or follow Pow operator
- || (operators.Peek() != OperatorKind.Pow)))
- {
- if (throwExceptionOnInvalidInput)
- {
- throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. An exponent must follow a unit or Pow operator. Invalid exponent at '" + c + "' at position " + pos.ToString());
- }
- else
- {
- // return null;
- inputRecognized = false;
- }
- }
- else
- {
- //// Try to read an exponent from input
-
- Int16 numLen = 1;
-
- int maxLen = Math.Min(inputString.Length - pos, 1 + 3); // Max length of sign and digits to look for
- while (numLen < maxLen && Char.IsDigit(inputString[pos + numLen]))
- {
- numLen++;
- }
-
- SByte exponent;
- if (numLen > 0 && SByte.TryParse(inputString.Substring(pos, numLen), out exponent))
- {
- if ((lastReadToken == TokenKind.Operator)
- && (operators.Peek() == OperatorKind.Pow))
- {
- // Exponent follow Pow operator;
- // Remove Pow operator from operator stack since it is handled as implicit in parser.
- operators.Pop();
- }
-
- pos += numLen;
- afterLastOperandPos = pos;
-
- lastReadToken = TokenKind.Exponent;
-
- return new Token(exponent);
- }
- else
- {
- if (throwExceptionOnInvalidInput)
- {
- throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. Invalid or missing exponent after '" + c + "' at position " + pos.ToString());
- }
- else
- {
- // return null;
- inputRecognized = false;
- }
- }
- }
- }
- else
- {
- if ((lastReadToken == TokenKind.Operator) // Unit follow Pow operator;
- && (operators.Peek() == OperatorKind.Pow))
- {
- if (throwExceptionOnInvalidInput)
- {
- throw new PhysicalUnitFormatException("The string argument is not in a valid physical unit format. An unit must not follow an pow operator. Missing exponent at '" + c + "' at position " + pos.ToString());
- }
- else
- {
- inputRecognized = false;
- }
- }
- else
- {
- // Try to read a unit from input
- int maxLen = Math.Min(1 + 3, inputString.Length - pos); // Max length of scale and symbols to look for
-
- String tempStr = inputString.Substring(pos, maxLen);
- maxLen = tempStr.IndexOfAny(new Char[] { ' ', '*', '·', '/', '^', '+', '-', '(', ')' }); // '·' center dot '\0x0B7' (Char)183 U+00B7
- if (maxLen < 0)
- {
- maxLen = tempStr.Length;
- }
-
- for (int unitLen = maxLen; unitLen > 0; unitLen--)
- {
- String unitStr = tempStr.Substring(0, unitLen);
- Unit su = Physics.UnitSystems.ScaledUnitFromSymbol(unitStr);
- if (su != null)
- {
- if (lastReadToken == TokenKind.Unit)
- { // Assume implicit Mult operator
- PushNewOp…
Large files files are truncated, but you can click here to view the full file