Skip to content

Commit

Permalink
#308 - Units refactoring
Browse files Browse the repository at this point in the history
  • Loading branch information
sys27 committed Mar 12, 2022
1 parent 1d640ca commit 7df0c89
Show file tree
Hide file tree
Showing 12 changed files with 425 additions and 503 deletions.
63 changes: 58 additions & 5 deletions xFunc.Maths/Expressions/Units/PowerUnits/PowerUnit.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,78 @@
// Copyright (c) Dmytro Kyshchenko. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics.CodeAnalysis;

namespace xFunc.Maths.Expressions.Units.PowerUnits;

/// <summary>
/// Specifies a measurement of power.
/// Represents a power unit.
/// </summary>
public enum PowerUnit
public readonly struct PowerUnit : IEquatable<PowerUnit>
{
/// <summary>
/// Watt (W).
/// </summary>
Watt,
public static readonly PowerUnit Watt = new PowerUnit(1.0, "W");

/// <summary>
/// Kilowatt (kW).
/// </summary>
Kilowatt,
public static readonly PowerUnit Kilowatt = new PowerUnit(1000.0, "kW");

/// <summary>
/// Horsepower (hp).
/// </summary>
Horsepower,
public static readonly PowerUnit Horsepower = new PowerUnit(745.69987158227022, "hp");

private PowerUnit(double factor, string unitName)
{
Factor = factor;
UnitName = unitName;
}

/// <summary>
/// Determines whether two specified instances of <see cref="PowerUnit"/> are equal.
/// </summary>
/// <param name="left">The first object to compare.</param>
/// <param name="right">The second object to compare.</param>
/// <returns><c>true</c> if <paramref name="left"/> is equal to <paramref name="right"/>; otherwise, <c>false</c>.</returns>
public static bool operator ==(PowerUnit left, PowerUnit right)
=> left.Equals(right);

/// <summary>
/// Determines whether two specified instances of <see cref="PowerUnit"/> are equal.
/// </summary>
/// <param name="left">The first object to compare.</param>
/// <param name="right">The second object to compare.</param>
/// <returns><c>true</c> if <paramref name="left"/> is equal to <paramref name="right"/>; otherwise, <c>false</c>.</returns>
public static bool operator !=(PowerUnit left, PowerUnit right)
=> !left.Equals(right);

/// <inheritdoc />
public bool Equals(PowerUnit other)
=> Factor.Equals(other.Factor) && UnitName == other.UnitName;

/// <inheritdoc />
public override bool Equals(object? obj)
=> obj is PowerUnit other && Equals(other);

/// <inheritdoc />
[ExcludeFromCodeCoverage]
public override int GetHashCode()
=> HashCode.Combine(Factor, UnitName);

/// <inheritdoc />
public override string ToString()
=> UnitName;

/// <summary>
/// Gets a factor of conversion from this unit to base unit.
/// </summary>
public double Factor { get; }

/// <summary>
/// Gets a short name of the unit.
/// </summary>
public string UnitName { get; }
}
114 changes: 41 additions & 73 deletions xFunc.Maths/Expressions/Units/PowerUnits/PowerValue.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
// Copyright (c) Dmytro Kyshchenko. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics.CodeAnalysis;

namespace xFunc.Maths.Expressions.Units.PowerUnits;

/// <summary>
Expand Down Expand Up @@ -69,7 +71,12 @@ public static PowerValue Horsepower(NumberValue numberValue)

/// <inheritdoc />
public bool Equals(PowerValue other)
=> Value == other.Value && Unit == other.Unit;
{
var inBase = ToBase();
var otherInBase = other.ToBase();

return inBase.Value.Equals(otherInBase.Value);
}

/// <inheritdoc />
public override bool Equals(object? obj)
Expand All @@ -78,37 +85,29 @@ public override bool Equals(object? obj)
/// <inheritdoc />
public int CompareTo(PowerValue other)
{
var valueComparison = Value.CompareTo(other.Value);
if (valueComparison != 0)
return valueComparison;
var inBase = ToBase();
var otherInBase = other.ToBase();

return Unit.CompareTo(other.Unit);
return inBase.Value.CompareTo(otherInBase.Value);
}

/// <inheritdoc />
public int CompareTo(object? obj)
{
if (obj is null)
return 1;

if (obj is PowerValue other)
return CompareTo(other);

throw new ArgumentException($"Object must be of type {nameof(PowerValue)}");
}
public int CompareTo(object obj)
=> obj switch
{
null => 1,
PowerValue other => CompareTo(other),
_ => throw new ArgumentException($"Object must be of type {nameof(PowerValue)}"),
};

/// <inheritdoc />
[ExcludeFromCodeCoverage]
public override int GetHashCode()
=> HashCode.Combine(Value, (int)Unit);
=> HashCode.Combine(Value, Unit);

/// <inheritdoc />
public override string ToString() => Unit switch
{
PowerUnit.Watt => $"{Value} W",
PowerUnit.Kilowatt => $"{Value} kW",
PowerUnit.Horsepower => $"{Value} hp",
_ => throw new InvalidOperationException(),
};
public override string ToString()
=> $"{Value} {Unit}";

/// <summary>
/// Determines whether two specified instances of <see cref="PowerValue"/> are equal.
Expand Down Expand Up @@ -172,7 +171,7 @@ public override int GetHashCode()
/// <returns>An object that is the sum of <paramref name="left"/> and <paramref name="right"/>.</returns>
public static PowerValue operator +(PowerValue left, PowerValue right)
{
(left, right) = ToCommonUnits(left, right);
right = right.To(left.Unit);

return new PowerValue(left.Value + right.Value, left.Unit);
}
Expand All @@ -185,7 +184,7 @@ public override int GetHashCode()
/// <returns>An object that is the difference of <paramref name="left"/> and <paramref name="right"/>.</returns>
public static PowerValue operator -(PowerValue left, PowerValue right)
{
(left, right) = ToCommonUnits(left, right);
right = right.To(left.Unit);

return new PowerValue(left.Value - right.Value, left.Unit);
}
Expand All @@ -198,73 +197,42 @@ public override int GetHashCode()
public static PowerValue operator -(PowerValue value)
=> new PowerValue(-value.Value, value.Unit);

private static (PowerValue Left, PowerValue Right) ToCommonUnits(PowerValue left, PowerValue right)
{
var commonUnit = GetCommonUnit(left.Unit, right.Unit);

return (left.To(commonUnit), right.To(commonUnit));
}

private static PowerUnit GetCommonUnit(PowerUnit left, PowerUnit right)
=> (left, right) switch
{
_ when left == right => left,

(PowerUnit.Kilowatt, PowerUnit.Horsepower) or
(PowerUnit.Horsepower, PowerUnit.Kilowatt)
=> PowerUnit.Kilowatt,

_ => PowerUnit.Watt,
};
private PowerValue ToBase()
=> new PowerValue(Value * Unit.Factor, PowerUnit.Watt);

/// <summary>
/// Converts the current object to the specified <paramref name="unit"/>.
/// Convert to the <paramref name="newUnit"/> unit.
/// </summary>
/// <param name="unit">The unit to convert to.</param>
/// <returns>The power value which is converted to the specified <paramref name="unit"/>.</returns>
public PowerValue To(PowerUnit unit) => unit switch
/// <param name="newUnit">The new unit.</param>
/// <returns>The value in the new unit.</returns>
public PowerValue To(PowerUnit newUnit)
{
PowerUnit.Watt => ToWatt(),
PowerUnit.Kilowatt => ToKilowatt(),
PowerUnit.Horsepower => ToHorsepower(),
_ => throw new ArgumentOutOfRangeException(nameof(unit), unit, null),
};
var inBase = Value * Unit.Factor;
var converted = inBase / newUnit.Factor;

return new PowerValue(converted, newUnit);
}

/// <summary>
/// Converts the current object to watt.
/// </summary>
/// <returns>The power value which is converted to watts.</returns>
public PowerValue ToWatt() => Unit switch
{
PowerUnit.Watt => this,
PowerUnit.Kilowatt => Watt(Value * 1000.0),
PowerUnit.Horsepower => Watt(Value * 745.69987158227022),
_ => throw new InvalidOperationException(),
};
public PowerValue ToWatt()
=> To(PowerUnit.Watt);

/// <summary>
/// Converts the current object to kilowatt.
/// </summary>
/// <returns>The power value which is converted to kilowatts.</returns>
public PowerValue ToKilowatt() => Unit switch
{
PowerUnit.Watt => Kilowatt(Value / 1000.0),
PowerUnit.Kilowatt => this,
PowerUnit.Horsepower => Kilowatt(Value * 745.69987158227022 / 1000),
_ => throw new InvalidOperationException(),
};
public PowerValue ToKilowatt()
=> To(PowerUnit.Kilowatt);

/// <summary>
/// Converts the current object to horsepower.
/// </summary>
/// <returns>The power value which is converted to horsepowers.</returns>
public PowerValue ToHorsepower() => Unit switch
{
PowerUnit.Watt => Horsepower(Value / 745.69987158227022),
PowerUnit.Kilowatt => Horsepower(Value / 745.69987158227022 * 1000),
PowerUnit.Horsepower => this,
_ => throw new InvalidOperationException(),
};
public PowerValue ToHorsepower()
=> To(PowerUnit.Horsepower);

/// <summary>
/// Returns the absolute value of a specified power value.
Expand Down
73 changes: 68 additions & 5 deletions xFunc.Maths/Expressions/Units/TemperatureUnits/TemperatureUnit.cs
Original file line number Diff line number Diff line change
@@ -1,25 +1,88 @@
// Copyright (c) Dmytro Kyshchenko. All rights reserved.
// Licensed under the MIT license. See LICENSE file in the project root for full license information.

using System.Diagnostics.CodeAnalysis;

namespace xFunc.Maths.Expressions.Units.TemperatureUnits;

/// <summary>
/// Specifies a measurement of temperature.
/// Represents a temperature unit.
/// </summary>
public enum TemperatureUnit
public readonly struct TemperatureUnit : IEquatable<TemperatureUnit>
{
/// <summary>
/// Celsius (°C).
/// </summary>
Celsius,
public static readonly TemperatureUnit Celsius = new TemperatureUnit(x => x, x => x, "°C");

/// <summary>
/// Fahrenheit (°F).
/// </summary>
Fahrenheit,
public static readonly TemperatureUnit Fahrenheit = new TemperatureUnit(
x => (x - 32) * 5.0 / 9.0, x => x * 9.0 / 5.0 + 32, "°F");

/// <summary>
/// Kelvin (K).
/// </summary>
Kelvin,
public static readonly TemperatureUnit Kelvin = new TemperatureUnit(
x => x - 273.15, x => x + 273.15, "K");

private TemperatureUnit(Func<double, double> toBase, Func<double, double> fromBase, string unitName)
{
ToBase = toBase;
FromBase = fromBase;
UnitName = unitName;
}

/// <summary>
/// Determines whether two specified instances of <see cref="TemperatureUnit"/> are equal.
/// </summary>
/// <param name="left">The first object to compare.</param>
/// <param name="right">The second object to compare.</param>
/// <returns><c>true</c> if <paramref name="left"/> is equal to <paramref name="right"/>; otherwise, <c>false</c>.</returns>
public static bool operator ==(TemperatureUnit left, TemperatureUnit right)
=> left.Equals(right);

/// <summary>
/// Determines whether two specified instances of <see cref="TemperatureUnit"/> are equal.
/// </summary>
/// <param name="left">The first object to compare.</param>
/// <param name="right">The second object to compare.</param>
/// <returns><c>true</c> if <paramref name="left"/> is equal to <paramref name="right"/>; otherwise, <c>false</c>.</returns>
public static bool operator !=(TemperatureUnit left, TemperatureUnit right)
=> !left.Equals(right);

/// <inheritdoc />
public bool Equals(TemperatureUnit other)
=> ToBase.Equals(other.ToBase) &&
FromBase.Equals(other.FromBase) &&
UnitName == other.UnitName;

/// <inheritdoc />
public override bool Equals(object? obj)
=> obj is TemperatureUnit other && Equals(other);

/// <inheritdoc />
[ExcludeFromCodeCoverage]
public override int GetHashCode()
=> HashCode.Combine(ToBase, FromBase, UnitName);

/// <inheritdoc />
public override string ToString()
=> UnitName;

/// <summary>
/// Gets the conversion function from the current unit to the base unit.
/// </summary>
public Func<double, double> ToBase { get; }

/// <summary>
/// Gets the conversion function from the base unit to the current unit.
/// </summary>
public Func<double, double> FromBase { get; }

/// <summary>
/// Gets a short name of the unit.
/// </summary>
public string UnitName { get; }
}

0 comments on commit 7df0c89

Please sign in to comment.