Bases of a Recipe System created, tags compponet, and Tempearue stuct with a temutrae delta.

This commit is contained in:
2026-05-04 00:02:08 -04:00
parent 4a7494ff6b
commit d620189e4e
8 changed files with 1481 additions and 13 deletions

494
src/Math/Temperature.cs Normal file
View File

@@ -0,0 +1,494 @@
//https://www.codeproject.com/Articles/311333/A-Csharp-Temperature-Struct
namespace FoodFactory;
using System;
using System.Diagnostics.CodeAnalysis;
using System.Globalization;
using System.Numerics;
/// <summary>
/// Options for temperature measurement units.
/// </summary>
public enum TemperatureUnit
{
/// <summary>
/// The SI base unit of thermodynamic temperature,
/// equal in magnitude to the degree Celsius.
/// </summary>
Kelvin,
/// <summary>
/// A scale of temperature on which water freezes
/// at 0° and boils at 100° under standard conditions.
/// </summary>
Celsius,
/// <summary>
/// A scale of temperature on which water freezes at 32°
/// and boils at 212° under standard conditions.
/// </summary>
Fahrenheit
}
/// <summary>
/// A temperature value.
/// </summary>
public struct Temperature : IFormattable, IComparable,
IComparable<Temperature>, IEquatable<Temperature>,
IAdditionOperators<Temperature, TemperatureDelta, Temperature>,
ISubtractionOperators<Temperature, Temperature, TemperatureDelta>,
ISubtractionOperators<Temperature, TemperatureDelta, TemperatureDelta>,
IEqualityOperators<Temperature, Temperature, bool>,
IComparisonOperators<Temperature, Temperature, bool>
{
private double _kelvin;
/// <summary>
/// Creates a new temperature with the specified value in Kelvin.
/// </summary>
/// <param name="kelvin">The value of the temperature.</param>
public Temperature(double kelvin) : this() { _kelvin = kelvin; }
/// <summary>
/// Creates a new temperature with the specified value in the
/// specified unit of measurement.
/// </summary>
/// <param name="temperature">The value of the temperature.</param>
/// <param name="unit">The unit of measurement that defines how
/// the <paramref name="temperature"/> value is used.</param>
public Temperature(double temperature, TemperatureUnit unit)
: this()
{
switch (unit)
{
case TemperatureUnit.Kelvin:
_kelvin = temperature;
break;
case TemperatureUnit.Celsius:
Celsius = temperature;
break;
case TemperatureUnit.Fahrenheit:
Fahrenheit = temperature;
break;
default:
throw new ArgumentException(
"The temperature unit '" + unit.ToString() + "' is unknown.");
}
}
/// <summary>
/// Gets or sets the temperature value in Kelvin.
/// </summary>
public double Kelvin
{
readonly get => _kelvin;
set => _kelvin = value;
}
/// <summary>
/// Gets or sets the temperature value in Celsius.
/// </summary>
public double Celsius
{
readonly get => KelvinToCelsius(_kelvin); set => _kelvin = CelsiusToKelvin(value);
}
/// <summary>
/// Gets or sets the temperature value in Fahrenheit.
/// </summary>
public double Fahrenheit
{
readonly get => KelvinToFahrenheit(_kelvin); set => _kelvin = FahrenheitToKelvin(value);
}
/// <summary>
/// Gets the temperature value in the specified unit of measurement.
/// </summary>
/// <param name="unit">The unit of measurement
/// in which the temperature should be retrieved.</param>
/// <returns>The temperature value in the specified
/// <paramref name="unit"/>.</returns>
public readonly double ValueIn(TemperatureUnit unit) => unit switch
{
TemperatureUnit.Kelvin => _kelvin,
TemperatureUnit.Celsius => Celsius,
TemperatureUnit.Fahrenheit => Fahrenheit,
_ => throw new ArgumentException(
"Unknown temperature unit '" + unit.ToString() + "'."),
};
/// <summary>
/// Returns a string representation of the temperature value.
/// </summary>
/// <param name="format">
/// A single format specifier that indicates how to format the value of this
/// temperature. The format parameter can be "G",
/// "C", "F", or "K". If format
/// is null or the empty string (""), "G" is used.
/// </param>
/// <param name="provider">
/// An IFormatProvider reference that supplies culture-specific formatting
/// services.
/// </param>
/// <returns>A string representation of the temperature.</returns>
/// <exception cref="FormatException">
/// The value of format is not null, the empty string (""), "G", "C", "F", or
/// "K".
/// </exception>
public readonly string ToString(string? format, IFormatProvider? provider)
{
if (string.IsNullOrEmpty(format))
{
format = "G";
}
provider ??= CultureInfo.CurrentCulture;
return format switch
{
"G" or "C" or "g" or "c" => Celsius.ToString("F2", provider) + " °C",
"F" or "f" => Fahrenheit.ToString("F2", provider) + " °F",
"K" or "k" => _kelvin.ToString("F2", provider) + " K",
_ => throw new FormatException(
string.Format("The {0} format string is not supported.", format)),
};
}
/// <summary>
/// Returns a string representation of the temperature value.
/// </summary>
/// <param name="format">
/// A single format specifier that indicates how to format the value of this
/// temperature. The format parameter can be "G",
/// "C", "F", or "K". If format
/// is null or the empty string (""), "G" is used.
/// </param>
/// <returns>A string representation of the temperature.</returns>
/// <exception cref="FormatException">
/// The value of format is not null,
/// the empty string (""), "G", "C", "F", or
/// "K".
/// </exception>
public readonly string ToString(string format) => ToString(format, null);
/// <summary>
/// Returns a string representation of the temperature value.
/// </summary>
/// <returns>A string representation of the temperature.</returns>
public override readonly string ToString() => ToString(null, null);
/// <summary>
/// Returns a string representation of the temperature value.
/// </summary>
/// <param name="unit">
/// The temperature unit as which the temperature value should be displayed.
/// </param>
/// <param name="provider">
/// An IFormatProvider reference that supplies culture-specific formatting
/// services.
/// </param>
/// <returns>A string representation of the temperature.</returns>
public readonly string ToString(TemperatureUnit unit, IFormatProvider? provider)
{
return unit switch
{
TemperatureUnit.Celsius => ToString("C", provider),
TemperatureUnit.Fahrenheit => ToString("F", provider),
TemperatureUnit.Kelvin => ToString("K", provider),
_ => throw new FormatException("The temperature unit '" +
unit.ToString() + "' is unknown."),
};
}
/// <summary>
/// Returns a string representation of the temperature value.
/// </summary>
/// <param name="unit">
/// The temperature unit as which the temperature value should be displayed.
/// </param>
/// <returns>A string representation of the temperature.</returns>
public readonly string ToString(TemperatureUnit unit) => ToString(unit, null);
/// <summary>
/// Compares this instance to a specified Temperature object and returns an indication
/// of their relative values.
/// </summary>
/// <param name="value">A Temperature object
/// to compare to this instance.</param>
/// <returns>
/// A signed number indicating the relative values of this instance and value.
/// Value Description A negative integer This instance is less than value. Zero
/// This instance is equal to value. A positive integer This instance is greater
/// than value.
/// </returns>
public readonly int CompareTo(Temperature value) => _kelvin.CompareTo(value._kelvin);
/// <summary>
/// Compares this instance to a specified object and returns an indication of
/// their relative values.
/// </summary>
/// <param name="value">An object to compare, or null.</param>
/// <returns>
/// A signed number indicating the relative values of this instance and value.
/// Value Description A negative integer This instance is less than value. Zero
/// This instance is equal to value. A positive integer This instance is greater
/// than value, or value is null.
/// </returns>
/// <exception cref="ArgumentException">
/// The value is not a Temperature.
/// </exception>
public readonly int CompareTo(object? value)
{
if (value == null)
{
return 1;
}
if (value is not Temperature)
{
throw new ArgumentException($"Can not compare {value.GetType()} and {GetType()}");
}
return CompareTo((Temperature)value);
}
/// <summary>
/// Determines whether or not the given temperature is considered equal to this instance.
/// </summary>
/// <param name="value">The temperature to compare to this instance.</param>
/// <returns>True if the temperature is considered equal
/// to this instance. Otherwise, false.</returns>
public readonly bool Equals(Temperature value) => _kelvin == value._kelvin;
/// <summary>
/// Determines whether or not the given object is considered equal to the temperature.
/// </summary>
/// <param name="value">The object to compare to the temperature.</param>
/// <returns>True if the object is considered equal
/// to the temperature. Otherwise, false.</returns>
public override readonly bool Equals([NotNullWhen(true)] object? value) => value is Temperature temp && Equals(temp);
/// <summary>
/// Returns the hash code for this instance.
/// </summary>
/// <returns>A 32-bit signed integer hash code.</returns>
public override readonly int GetHashCode() => _kelvin.GetHashCode();
/// <summary>
/// Determines the equality of two temperatures.
/// </summary>
/// <param name="t1">The first temperature to be compared.</param>
/// <param name="t2">The second temperature to be compared.</param>
/// <returns>True if the temperatures are equal. Otherwise, false.</returns>
public static bool operator ==(Temperature t1, Temperature t2) => t1.Equals(t2);
/// <summary>
/// Determines the inequality of two temperatures.
/// </summary>
/// <param name="t1">The first temperature to be compared.</param>
/// <param name="t2">The second temperature to be compared.</param>
/// <returns>True if the temperatures are NOT equal. Otherwise, false.</returns>
public static bool operator !=(Temperature t1, Temperature t2) => !t1.Equals(t2);
/// <summary>
/// Determines whether one temperature is considered greater than another.
/// </summary>
/// <param name="t1">The first temperature to be compared.</param>
/// <param name="t2">The second temperature to be compared.</param>
/// <returns>True if the first temperature is greater than the second.
/// Otherwise, false.</returns>
public static bool operator >(Temperature t1, Temperature t2) => t1._kelvin > t2._kelvin;
/// <summary>
/// Determines whether one temperature is considered less than another.
/// </summary>
/// <param name="t1">The first temperature to be compared.</param>
/// <param name="t2">The second temperature to be compared.</param>
/// <returns>True if the first temperature is less than the second.
/// Otherwise, false.</returns>
public static bool operator <(Temperature t1, Temperature t2) => t1._kelvin < t2._kelvin;
/// <summary>
/// Determines whether one temperature is considered greater to or equal to another.
/// </summary>
/// <param name="t1">The first temperature to be compared.</param>
/// <param name="t2">The second temperature to be compared.</param>
/// <returns>
/// True if the first temperature is greater to or equal to the second. Otherwise, false.
/// </returns>
public static bool operator >=(Temperature t1, Temperature t2) => t1._kelvin >= t2._kelvin;
/// <summary>
/// Determines whether one temperature is considered less than or equal to another.
/// </summary>
/// <param name="t1">The first temperature to be compared.</param>
/// <param name="t2">The second temperature to be compared.</param>
/// <returns>
/// True if the first temperature is less than or equal to the second. Otherwise, false.
/// </returns>
public static bool operator <=(Temperature t1, Temperature t2) => t1._kelvin <= t2._kelvin;
/// <summary>
/// Adds two instances of the temperature object.
/// </summary>
/// <param name="t1">The temperature on the left-hand side of the operator.
/// </param>
/// <param name="t2">The temperature on the right-hand side of the operator.
/// </param>
/// <returns>The sum of the two temperatures.</returns>
public static Temperature operator +(Temperature t1, TemperatureDelta t2) => new(t1._kelvin + t2.KelvinDelta);
/// <summary>
/// Subtracts one instance from another.
/// </summary>
/// <param name="t1">The temperature on the left-hand side of the operator.
/// </param>
/// <param name="t2">The temperature on the right-hand side of the operator.
/// </param>
/// <returns>The difference of the two temperatures.</returns>
public static TemperatureDelta operator -(Temperature t1, Temperature t2) => new(t1._kelvin - t2._kelvin);
public static TemperatureDelta operator -(Temperature left, TemperatureDelta right) => new(left._kelvin - right.KelvinDelta);
/// <summary>
/// Converts a Kelvin temperature value to Celsius.
/// </summary>
/// <param name="kelvin">The Kelvin value to convert to Celsius.
/// </param>
/// <returns>The Kelvin value in Celsius.</returns>
public static double KelvinToCelsius(double kelvin) => kelvin - 273.15;
/// <summary>
/// Converts a Celsius value to Kelvin.
/// </summary>
/// <param name="celsius">The Celsius value to convert to Kelvin.
/// </param>
/// <returns>The Celsius value in Kelvin.</returns>
public static double CelsiusToKelvin(double celsius) => celsius + 273.15;
/// <summary>
/// Converts a Kelvin value to Fahrenheit.
/// </summary>
/// <param name="kelvin">The Kelvin value to convert to Fahrenheit.
/// </param>
/// <returns>The Kelvin value in Fahrenheit.</returns>
public static double KelvinToFahrenheit(double kelvin) => (kelvin * 9 / 5) - 459.67;
/// <summary>
/// Converts a Fahrenheit value to Kelvin.
/// </summary>
/// <param name="fahrenheit">The Fahrenheit value to convert to Kelvin.
/// </param>
/// <returns>The Fahrenheit value in Kelvin.</returns>
public static double FahrenheitToKelvin(double fahrenheit) => (fahrenheit + 459.67) * 5 / 9;
/// <summary>
/// Converts a Fahrenheit value to Celsius.
/// </summary>
/// <param name="fahrenheit">The Fahrenheit value to convert to Celsius.
/// </param>
/// <returns>The Fahrenheit value in Celsius.</returns>
public static double FahrenheitToCelsius(double fahrenheit) => (fahrenheit - 32) * 5 / 9;
/// <summary>
/// Converts a Celsius value to Fahrenheit.
/// </summary>
/// <param name="celsius">The Celsius value to convert to Fahrenheit.
/// </param>
/// <returns>The Celsius value in Fahrenheit.</returns>
public static double CelsiusToFahrenheit(double celsius) => (celsius * 9 / 5) + 32;
}
public readonly struct TemperatureDelta : IFormattable, IComparable,
IComparable<TemperatureDelta>, IEquatable<TemperatureDelta>,
IComparisonOperators<TemperatureDelta, TemperatureDelta, bool>,
IEqualityOperators<TemperatureDelta, TemperatureDelta, bool>,
IAdditionOperators<TemperatureDelta, TemperatureDelta, TemperatureDelta>,
ISubtractionOperators<TemperatureDelta, TemperatureDelta, TemperatureDelta>,
IMultiplyOperators<TemperatureDelta, double, TemperatureDelta>,
IDivisionOperators<TemperatureDelta, double, TemperatureDelta>
{
private readonly double _kelvinDelta;
public TemperatureDelta(double kelvin)
{
_kelvinDelta = kelvin;
}
public readonly double KelvinDelta => _kelvinDelta;
public readonly double FahrenheitDelta => CelsiusToFahrenheitDelta(_kelvinDelta);
public readonly double CelsiusDelta => _kelvinDelta;
public TemperatureDelta(double temperature, TemperatureUnit unit)
{
_kelvinDelta = unit switch
{
TemperatureUnit.Celsius => temperature,
TemperatureUnit.Fahrenheit => FahrenheitToKelvinDelta(temperature),
TemperatureUnit.Kelvin => temperature,
_ => throw new ArgumentException($"Unit {unit} is not a valid {nameof(TemperatureUnit)}"),
};
}
public static double FahrenheitToKelvinDelta(double fahrenheit) => fahrenheit * 5 / 9;
public static double KelvinToFahrenheitDelta(double kelvin) => kelvin * 9 / 5;
public static double FahrenheitToCelsiusDelta(double fahrenheit) => FahrenheitToKelvinDelta(fahrenheit);
public static double CelsiusToFahrenheitDelta(double celsius) => KelvinToFahrenheitDelta(celsius);
public bool Equals(TemperatureDelta other) => _kelvinDelta == other._kelvinDelta;
public override bool Equals([NotNullWhen(true)] object? obj) => obj is TemperatureDelta delta && Equals(delta);
public override int GetHashCode() => _kelvinDelta.GetHashCode();
public readonly string ToString(string? format, IFormatProvider? provider)
{
if (string.IsNullOrEmpty(format))
{
format = "G";
}
provider ??= CultureInfo.CurrentCulture;
return format switch
{
"G" or "C" or "g" or "c" => CelsiusDelta.ToString("F2", provider) + " °C",
"F" or "f" => FahrenheitDelta.ToString("F2", provider) + " °F",
"K" or "k" => _kelvinDelta.ToString("F2", provider) + " K",
_ => throw new FormatException(
string.Format("The {0} format string is not supported.", format)),
};
}
public readonly string ToString(string format) => ToString(format, null);
public override string ToString() => ToString(null, null);
public readonly int CompareTo(TemperatureDelta value) => _kelvinDelta.CompareTo(value._kelvinDelta);
public readonly int CompareTo(object? value)
{
if (value == null)
{
return 1;
}
if (value is not TemperatureDelta)
{
throw new ArgumentException(
$"Object must be of type {nameof(TemperatureDelta)}",
nameof(value));
}
return CompareTo((TemperatureDelta)value);
}
public static TemperatureDelta operator +(TemperatureDelta left, TemperatureDelta right) => new(left._kelvinDelta + right._kelvinDelta);
public static TemperatureDelta operator -(TemperatureDelta left, TemperatureDelta right) => new(left._kelvinDelta - right._kelvinDelta);
public static TemperatureDelta operator *(TemperatureDelta left, double right) => new(left._kelvinDelta * right);
public static TemperatureDelta operator /(TemperatureDelta left, double right) => new(left._kelvinDelta / right);
public static bool operator >(TemperatureDelta left, TemperatureDelta right) => left._kelvinDelta > right._kelvinDelta;
public static bool operator >=(TemperatureDelta left, TemperatureDelta right) => left._kelvinDelta >= right._kelvinDelta;
public static bool operator <(TemperatureDelta left, TemperatureDelta right) => left._kelvinDelta < right._kelvinDelta;
public static bool operator <=(TemperatureDelta left, TemperatureDelta right) => left._kelvinDelta <= right._kelvinDelta;
public static bool operator ==(TemperatureDelta left, TemperatureDelta right) => left._kelvinDelta == right._kelvinDelta;
public static bool operator !=(TemperatureDelta left, TemperatureDelta right) => left._kelvinDelta != right._kelvinDelta;
}