protected MetricUnit() { //access the SIUnitAttribute MemberInfo info = this.GetType(); object[] attributes = (object[])info.GetCustomAttributes(true); //get the UnitAttribute MetricUnitAttribute siua = (MetricUnitAttribute)attributes.SingleOrDefault <object>(ut => ut is MetricUnitAttribute); if (siua != null) { defaultUnitPrefix = MetricPrefix.FromPrefixName(siua.SiPrefix.ToString()); unitPrefix = MetricPrefix.FromPrefixName(siua.SiPrefix.ToString()); } else { throw new UnitException("SIUnitAttribute Not Found"); } //ReferenceUnit attribute may or may not appear // if it appears then the unit is not a default SI unit // but act as SI Unit {means take prefixes}. and accepted by the SI poids // however the code of reference unit is in the base class code. }
public static MetricPrefix Divide(MetricPrefix firstPrefix, MetricPrefix secondPrefix) { int exp = firstPrefix.Exponent / secondPrefix.Exponent; CheckExponent(exp); MetricPrefix prefix = MetricPrefix.FromExponent(exp); return(prefix); }
private static AnyQuantity <double> MakeQuantity(MetricUnit unit, MetricPrefix siPrefix, double value) { //assign its prefix unit.UnitPrefix = siPrefix; //create the corresponding quantity AnyQuantity <double> qty = unit.GetThisUnitQuantity <double>(); //assign the unit to the created quantity qty.Unit = unit; //assign the value to the quantity qty.Value = value; return(qty); }
/// <summary> /// Check the exponent if it can found or /// if it exceeds 24 or precedes -25 <see cref="MetricPrefixException"/> occur with the closest /// <see cref="MetricPrefix"/> and overflow the rest of it. /// </summary> /// <param name="exp"></param> public static void CheckExponent(double expo) { int exp = (int)Math.Floor(expo); double ov = expo - exp; if (exp > 24) { throw new MetricPrefixException("Exponent Exceed 24") { WrongExponent = exp, CorrectPrefix = MetricPrefix.FromExponent(24), OverflowExponent = (exp - 24) + ov } } ; if (exp < -24) { throw new MetricPrefixException("Exponent Precede -24") { WrongExponent = exp, CorrectPrefix = MetricPrefix.FromExponent(-24), OverflowExponent = (exp + 24) + ov } } ; int[] wrongexp = { 4, 5, 7, 8, 10, 11, 13, 14, 16, 17, 19, 20, 22, 23 }; int[] correctexp = { 3, 3, 6, 6, 9, 9, 12, 12, 15, 15, 18, 18, 21, 21 }; for (int i = 0; i < wrongexp.Length; i++) { //find if exponent in wrong powers if (Math.Abs(exp) == wrongexp[i]) { int cexp = 0; if (exp > 0) { cexp = correctexp[i]; } if (exp < 0) { cexp = -1 * correctexp[i]; } throw new MetricPrefixException("Exponent not aligned") { WrongExponent = exp, CorrectPrefix = MetricPrefix.FromExponent(cexp), OverflowExponent = (exp - cexp) + ov //5-3 = 2 , -5--3 =-2 }; } } if (ov != 0) { //then the exponent must be 0.5 throw new MetricPrefixException("Exponent not aligned") { WrongExponent = exp, CorrectPrefix = MetricPrefix.FromExponent(0), OverflowExponent = ov //5-3 = 2 , -5--3 =-2 }; } } } }
/// <summary> /// Gets the factor to convert to the required prefix. /// </summary> /// <param name="prefix"></param> /// <returns>Conversion factor</returns> public double GetFactorForConvertTo(MetricPrefix prefix) { return(prefix.Factor / this.Factor); }
public MetricPrefix Invert() { return(MetricPrefix.FromExponent(0 - this.PrefixExponent)); }
/// <summary> /// Group all similar units so it remove units that reached exponent zero /// also keep track of prefixes of metric units. /// </summary> /// <param name="bulk_units"></param> /// <returns></returns> private List <Unit> GroupUnits(List <Unit> bulk_units) { List <Unit> units = FlattenUnits(bulk_units); if (units.Count == 1) { return(units); } List <Unit> GroupedUnits = new List <Unit>(); Dictionary <Type, Unit> us = new Dictionary <Type, Unit>(); foreach (Unit un in units) { if (us.ContainsKey(un.GetType())) { //check for prefixes before accumulating units // otherwise I'll lose the UnitExponent value. if (un is MetricUnit) { //check prefixes to consider milli+Mega for example for overflow MetricPrefix accumPrefix = ((MetricUnit)us[un.GetType()]).UnitPrefix; MetricPrefix sourcePrefix = ((MetricUnit)un).UnitPrefix; try { //Word about MetricPrefix // The prefix takes the unit exponent as another exponent to it // so if we are talking about cm^2 actually it is c^2*m^2 // suppose we multiply cm*cm this will give cm^2 // so no need to alter the prefix value // however remain a problem of different prefixes // for example km * cm = ?m^2 // k*c = ?^2 // so ? = (k+c)/2 ;) // if there is a fraction remove the prefixes totally and substitute them // in the overflow flag. // about division // km / cm = ?<1> // k/c = ? or in exponent k-c=? double targetExponent = us[un.GetType()].unitExponent + un.unitExponent; double accumExponent = accumPrefix.Exponent * us[un.GetType()].unitExponent; double sourceExponent = sourcePrefix.Exponent * un.unitExponent; double resultExponent = (accumExponent + sourceExponent); if (!(us[un.GetType()].IsInverted ^ un.IsInverted)) { //multiplication if (resultExponent % targetExponent == 0) { //we can get the symbol of the sqrt of this double unknown = resultExponent / targetExponent; ((MetricUnit)us[un.GetType()]).UnitPrefix = MetricPrefix.FromExponent(unknown); } else { //we can't get the approriate symbol because we have a fraction // like kilo * centi = 3-2=1 1/2=0.5 or 1%2=1 // so we will take the whole fraction and make an overflow ((MetricUnit)us[un.GetType()]).UnitPrefix = MetricPrefix.None; if (resultExponent != 0) { unitOverflow += Math.Pow(10, resultExponent); _IsOverflowed = true; } } } else { //division //resultExponent = (accumExponent - sourceExponent); ((MetricUnit)us[un.GetType()]).UnitPrefix = MetricPrefix.None; if (resultExponent != 0) //don't overflow in case of zero exponent target because there is not prefix in this case { unitOverflow += Math.Pow(10, resultExponent); _IsOverflowed = true; } } } catch (MetricPrefixException mpe) { ((MetricUnit)us[un.GetType()]).UnitPrefix = mpe.CorrectPrefix; unitOverflow += Math.Pow(10, mpe.OverflowExponent); _IsOverflowed = true; } } us[un.GetType()].UnitExponent += un.UnitExponent; us[un.GetType()].UnitDimension += un.UnitDimension; } else { us[un.GetType()] = (Unit)un.MemberwiseClone(); } } foreach (Unit un in us.Values) { if (un.UnitExponent != 0) { GroupedUnits.Add(un); } else { //zero means units should be skipped // however we are testing for prefix if the unit is metric // if the unit is metric and deprecated the prefix should be taken into consideration if (un is MetricUnit) { MetricUnit mu = (MetricUnit)un; if (mu.UnitPrefix.Exponent != 0) { _IsOverflowed = true; unitOverflow += Math.Pow(10, mu.UnitPrefix.Exponent); } } } } return(GroupedUnits); }
/// <summary> /// Returns the unit corresponding to the passed string. /// Suppors units with exponent. /// </summary> /// <param name="unit"></param> /// <returns></returns> internal static Unit ParseUnit(string un) { if (un == "1") { //this is dimensionless value return(new Unit(typeof(Quantities.DimensionlessQuantities.DimensionlessQuantity <>))); } //find '^' string[] upower = un.Split('^'); string unit = upower[0]; int power = 1; if (upower.Length > 1) { power = int.Parse(upower[1], CultureInfo.InvariantCulture); } Unit FinalUnit = null; //Phase 1: try direct mapping. try { FinalUnit = FindUnit(unit); } catch (UnitNotFoundException) { //try to find if it as a Metric unit with prefix //loop through all prefixes. for (int i = 10; i >= -10; i -= 1) { if (i == 0) { i--; //skip the None prefix } if (unit.StartsWith(MetricPrefix.GetPrefix(i).Symbol, StringComparison.Ordinal)) { //found MetricPrefix mp = MetricPrefix.GetPrefix(i); string upart = unit.Substring(mp.Symbol.Length); //then it should be MetricUnit otherwise die :) MetricUnit u = FindUnit(upart) as MetricUnit; if (u == null) { goto nounit; } u.UnitPrefix = mp; FinalUnit = u; break; } } } if (FinalUnit == null) { goto nounit; } if (power > 1) { //discover the new type QuantityDimension ud = FinalUnit.UnitDimension * power; Unit[] chobits = new Unit[power]; //what is chobits any way :O for (int iy = 0; iy < power; iy++) { chobits[iy] = (Unit)FinalUnit.MemberwiseClone(); } Type uQType = null; uQType = QuantityDimension.GetQuantityTypeFrom(ud); FinalUnit = new Unit(uQType, chobits); } return(FinalUnit); nounit: throw new UnitNotFoundException(un); }