//******************************************************************************************************
// Temperature.cs - Gbtc
//
// Copyright © 2012, Grid Protection Alliance. All Rights Reserved.
//
// Licensed to the Grid Protection Alliance (GPA) under one or more contributor license agreements. See
// the NOTICE file distributed with this work for additional information regarding copyright ownership.
// The GPA licenses this file to you under the MIT License (MIT), the "License"; you may
// not use this file except in compliance with the License. You may obtain a copy of the License at:
//
// http://www.opensource.org/licenses/MIT
//
// Unless agreed to in writing, the subject software distributed under the License is distributed on an
// "AS-IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. Refer to the
// License for the specific language governing permissions and limitations.
//
// Code Modification History:
// ----------------------------------------------------------------------------------------------------
// 01/25/2008 - J. Ritchie Carroll
// Initial version of source generated.
// 09/11/2008 - J. Ritchie Carroll
// Converted to C#.
// 08/10/2009 - Josh L. Patterson
// Edited Comments.
// 09/14/2009 - Stephen C. Wills
// Added new header and license agreement.
// 12/14/2012 - Starlynn Danyelle Gilliam
// Modified Header.
// 10/03/2017 - J. Ritchie Carroll
// Added units enumeration with associated Convert method.
//
//******************************************************************************************************
#region [ Contributor License Agreements ]
/**************************************************************************\
Copyright © 2009 - J. Ritchie Carroll
All rights reserved.
Redistribution and use in source and binary forms, with or without
modification, are permitted provided that the following conditions
are met:
* Redistributions of source code must retain the above copyright
notice, this list of conditions and the following disclaimer.
* Redistributions in binary form must reproduce the above
copyright notice, this list of conditions and the following
disclaimer in the documentation and/or other materials provided
with the distribution.
THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDER "AS IS" AND ANY
EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR
CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY
OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\**************************************************************************/
#endregion
using System;
using System.ComponentModel;
using System.Globalization;
using System.Runtime.CompilerServices;
namespace GSF.Units
{
#region [ Enumerations ]
///
/// Represents the units available for a value.
///
public enum TemperatureUnit
{
///
/// Kelvin temperature units.
///
Kelvin,
///
/// Celsius temperature units.
///
Celsius,
///
/// Fahrenheit temperature units.
///
Fahrenheit,
///
/// Newton temperature units.
///
Newton,
///
/// Rankine temperature units.
///
Rankine,
///
/// Delisle temperature units.
///
Delisle,
///
/// Réaumur temperature units.
///
Réaumur,
///
/// Rømer temperature units.
///
Rømer
}
#endregion
///
/// Represents a temperature, in Kelvin, as a double-precision floating-point number.
///
///
/// This class behaves just like a representing a temperature in Kelvin; it is implicitly
/// castable to and from a and therefore can be generally used "as" a double, but it
/// has the advantage of handling conversions to and from other temperature representations, specifically
/// Celsius, Fahrenheit, Newton, Rankine, Delisle, Réaumur and Rømer.
///
/// This example converts Celsius to Fahrenheit:
///
/// public double GetFahrenheit(double celsius)
/// {
/// return Temperature.FromCelsius(celsius).ToFahrenheit();
/// }
///
///
///
[Serializable]
public struct Temperature : IComparable, IFormattable, IConvertible, IComparable, IComparable, IEquatable, IEquatable
{
#region [ Members ]
// Constants
private const double CelsiusFactor = 1.0D;
private const double CelsiusOffset = 273.15D;
private const double CelsiusStep = 0.0D;
private const double FahrenheitFactor = 5.0D / 9.0D;
private const double FahrenheitOffset = 0.0D;
private const double FahrenheitStep = 459.67D;
private const double NewtonFactor = 100.0D / 33.0D;
private const double NewtonOffset = CelsiusOffset;
private const double NewtonStep = 0.0D;
private const double RankineFactor = FahrenheitFactor;
private const double RankineOffset = 0.0D;
private const double RankineStep = 0.0D;
private const double DelisleFactor = -2.0D / 3.0D;
private const double DelisleOffset = 373.15D;
private const double DelisleStep = 0.0D;
private const double RéaumurFactor = 5.0D / 4.0D;
private const double RéaumurOffset = CelsiusOffset;
private const double RéaumurStep = 0.0D;
private const double RømerFactor = 40.0D / 21.0D;
private const double RømerOffset = CelsiusOffset;
private const double RømerStep = -7.5D;
// Fields
private readonly double m_value; // Temperature value stored in Kelvin
#endregion
#region [ Constructors ]
///
/// Creates a new .
///
/// New temperature value in Kelvin.
public Temperature(double value)
{
m_value = value;
}
#endregion
#region [ Methods ]
///
/// Gets the value in Celsius.
///
/// Value of in Celsius.
public double ToCelsius()
{
return ToTemperature(CelsiusFactor, CelsiusOffset, CelsiusStep);
}
///
/// Gets the value in Fahrenheit.
///
/// Value of in Fahrenheit.
public double ToFahrenheit()
{
return ToTemperature(FahrenheitFactor, FahrenheitOffset, FahrenheitStep);
}
///
/// Gets the value in Newton.
///
/// Value of in Newton.
public double ToNewton()
{
return ToTemperature(NewtonFactor, NewtonOffset, NewtonStep);
}
///
/// Gets the value in Rankine.
///
/// Value of in Rankine.
public double ToRankine()
{
return ToTemperature(RankineFactor, RankineOffset, RankineStep);
}
///
/// Gets the value in Delisle.
///
/// Value of in Delisle.
public double ToDelisle()
{
return ToTemperature(DelisleFactor, DelisleOffset, DelisleStep);
}
///
/// Gets the value in Réaumur.
///
/// Value of in Réaumur.
public double ToRéaumur()
{
return ToTemperature(RéaumurFactor, RéaumurOffset, RéaumurStep);
}
///
/// Gets the value in Rømer.
///
/// Value of in Rømer.
public double ToRømer()
{
return ToTemperature(RømerFactor, RømerOffset, RømerStep);
}
///
/// Converts the to the specified .
///
/// Target units.
/// converted to .
public double ConvertTo(TemperatureUnit targetUnit)
{
switch (targetUnit)
{
case TemperatureUnit.Kelvin:
return m_value;
case TemperatureUnit.Celsius:
return ToCelsius();
case TemperatureUnit.Fahrenheit:
return ToFahrenheit();
case TemperatureUnit.Newton:
return ToNewton();
case TemperatureUnit.Rankine:
return ToRankine();
case TemperatureUnit.Delisle:
return ToDelisle();
case TemperatureUnit.Réaumur:
return ToRéaumur();
case TemperatureUnit.Rømer:
return ToRømer();
default:
throw new ArgumentOutOfRangeException(nameof(targetUnit), targetUnit, null);
}
}
// Calculate temperature based on value = (K - offset) / factor - step
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private Temperature ToTemperature(double factor, double offset, double step)
{
return (m_value - offset) / factor - step;
}
#region [ Numeric Interface Implementations ]
///
/// Compares this instance to a specified object and returns an indication of their relative values.
///
/// An object to compare, or null.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
/// value is not a or .
public int CompareTo(object value)
{
if (value == null)
return 1;
double num;
if (value is double)
num = (double)value;
else if (value is Temperature)
num = (Temperature)value;
else
throw new ArgumentException("Argument must be a Double or a Temperature");
return m_value < num ? -1 : (m_value > num ? 1 : 0);
}
///
/// Compares this instance to a specified and returns an indication of their
/// relative values.
///
/// A to compare.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
public int CompareTo(Temperature value)
{
return CompareTo((double)value);
}
///
/// Compares this instance to a specified and returns an indication of their
/// relative values.
///
/// A to compare.
///
/// A signed number indicating the relative values of this instance and value. Returns less than zero
/// if this instance is less than value, zero if this instance is equal to value, or greater than zero
/// if this instance is greater than value.
///
public int CompareTo(double value)
{
return m_value < value ? -1 : (m_value > value ? 1 : 0);
}
///
/// Returns a value indicating whether this instance is equal to a specified object.
///
/// An object to compare, or null.
///
/// True if obj is an instance of or and equals the value of this instance;
/// otherwise, False.
///
public override bool Equals(object obj)
{
if (obj is double)
return Equals((double)obj);
if (obj is Temperature)
return Equals((Temperature)obj);
return false;
}
///
/// Returns a value indicating whether this instance is equal to a specified value.
///
/// A value to compare to this instance.
///
/// True if obj has the same value as this instance; otherwise, False.
///
public bool Equals(Temperature obj)
{
return Equals((double)obj);
}
///
/// Returns a value indicating whether this instance is equal to a specified value.
///
/// A value to compare to this instance.
///
/// True if obj has the same value as this instance; otherwise, False.
///
public bool Equals(double obj)
{
return m_value == obj;
}
///
/// Returns the hash code for this instance.
///
///
/// A 32-bit signed integer hash code.
///
public override int GetHashCode()
{
return m_value.GetHashCode();
}
///
/// Converts the numeric value of this instance to its equivalent string representation.
///
///
/// The string representation of the value of this instance, consisting of a minus sign if
/// the value is negative, and a sequence of digits ranging from 0 to 9 with no leading zeros.
///
public override string ToString()
{
return m_value.ToString();
}
///
/// Converts the numeric value of this instance to its equivalent string representation, using
/// the specified format.
///
/// A format string.
///
/// The string representation of the value of this instance as specified by format.
///
public string ToString(string format)
{
return m_value.ToString(format);
}
///
/// Converts the numeric value of this instance to its equivalent string representation using the
/// specified culture-specific format information.
///
///
/// A that supplies culture-specific formatting information.
///
///
/// The string representation of the value of this instance as specified by provider.
///
public string ToString(IFormatProvider provider)
{
return m_value.ToString(provider);
}
///
/// Converts the numeric value of this instance to its equivalent string representation using the
/// specified format and culture-specific format information.
///
/// A format specification.
///
/// A that supplies culture-specific formatting information.
///
///
/// The string representation of the value of this instance as specified by format and provider.
///
public string ToString(string format, IFormatProvider provider)
{
return m_value.ToString(format, provider);
}
///
/// Converts the string representation of a number to its equivalent.
///
/// A string containing a number to convert.
///
/// A equivalent to the number contained in s.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in the correct format.
public static Temperature Parse(string s)
{
return double.Parse(s);
}
///
/// Converts the string representation of a number in a specified style to its equivalent.
///
/// A string containing a number to convert.
///
/// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
///
///
/// A equivalent to the number contained in s.
///
///
/// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
/// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in a format compliant with style.
public static Temperature Parse(string s, NumberStyles style)
{
return double.Parse(s, style);
}
///
/// Converts the string representation of a number in a specified culture-specific format to its equivalent.
///
/// A string containing a number to convert.
///
/// A that supplies culture-specific formatting information about s.
///
///
/// A equivalent to the number contained in s.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in the correct format.
public static Temperature Parse(string s, IFormatProvider provider)
{
return double.Parse(s, provider);
}
///
/// Converts the string representation of a number in a specified style and culture-specific format to its equivalent.
///
/// A string containing a number to convert.
///
/// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
///
///
/// A that supplies culture-specific formatting information about s.
///
///
/// A equivalent to the number contained in s.
///
///
/// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
/// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
///
/// s is null.
///
/// s represents a number less than or greater than .
///
/// s is not in a format compliant with style.
public static Temperature Parse(string s, NumberStyles style, IFormatProvider provider)
{
return double.Parse(s, style, provider);
}
///
/// Converts the string representation of a number to its equivalent. A return value
/// indicates whether the conversion succeeded or failed.
///
/// A string containing a number to convert.
///
/// When this method returns, contains the value equivalent to the number contained in s,
/// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null,
/// is not of the correct format, or represents a number less than or greater than .
/// This parameter is passed uninitialized.
///
/// true if s was converted successfully; otherwise, false.
public static bool TryParse(string s, out Temperature result)
{
double parseResult;
bool parseResponse;
parseResponse = double.TryParse(s, out parseResult);
result = parseResult;
return parseResponse;
}
///
/// Converts the string representation of a number in a specified style and culture-specific format to its
/// equivalent. A return value indicates whether the conversion succeeded or failed.
///
/// A string containing a number to convert.
///
/// A bitwise combination of System.Globalization.NumberStyles values that indicates the permitted format of s.
///
///
/// When this method returns, contains the value equivalent to the number contained in s,
/// if the conversion succeeded, or zero if the conversion failed. The conversion fails if the s parameter is null,
/// is not in a format compliant with style, or represents a number less than or
/// greater than . This parameter is passed uninitialized.
///
///
/// A object that supplies culture-specific formatting information about s.
///
/// true if s was converted successfully; otherwise, false.
///
/// style is not a System.Globalization.NumberStyles value. -or- style is not a combination of
/// System.Globalization.NumberStyles.AllowHexSpecifier and System.Globalization.NumberStyles.HexNumber values.
///
public static bool TryParse(string s, NumberStyles style, IFormatProvider provider, out Temperature result)
{
double parseResult;
bool parseResponse;
parseResponse = double.TryParse(s, style, provider, out parseResult);
result = parseResult;
return parseResponse;
}
///
/// Returns the for value type .
///
/// The enumerated constant, .
public TypeCode GetTypeCode()
{
return TypeCode.Double;
}
#region [ Explicit IConvertible Implementation ]
// These are explicitly implemented on the native System.Double implementations, so we do the same...
bool IConvertible.ToBoolean(IFormatProvider provider)
{
return Convert.ToBoolean(m_value, provider);
}
char IConvertible.ToChar(IFormatProvider provider)
{
return Convert.ToChar(m_value, provider);
}
sbyte IConvertible.ToSByte(IFormatProvider provider)
{
return Convert.ToSByte(m_value, provider);
}
byte IConvertible.ToByte(IFormatProvider provider)
{
return Convert.ToByte(m_value, provider);
}
short IConvertible.ToInt16(IFormatProvider provider)
{
return Convert.ToInt16(m_value, provider);
}
ushort IConvertible.ToUInt16(IFormatProvider provider)
{
return Convert.ToUInt16(m_value, provider);
}
int IConvertible.ToInt32(IFormatProvider provider)
{
return Convert.ToInt32(m_value, provider);
}
uint IConvertible.ToUInt32(IFormatProvider provider)
{
return Convert.ToUInt32(m_value, provider);
}
long IConvertible.ToInt64(IFormatProvider provider)
{
return Convert.ToInt64(m_value, provider);
}
ulong IConvertible.ToUInt64(IFormatProvider provider)
{
return Convert.ToUInt64(m_value, provider);
}
float IConvertible.ToSingle(IFormatProvider provider)
{
return Convert.ToSingle(m_value, provider);
}
double IConvertible.ToDouble(IFormatProvider provider)
{
return m_value;
}
decimal IConvertible.ToDecimal(IFormatProvider provider)
{
return Convert.ToDecimal(m_value, provider);
}
DateTime IConvertible.ToDateTime(IFormatProvider provider)
{
return Convert.ToDateTime(m_value, provider);
}
object IConvertible.ToType(Type type, IFormatProvider provider)
{
return Convert.ChangeType(m_value, type, provider) ?? Activator.CreateInstance(type);
}
#endregion
#endregion
#endregion
#region [ Operators ]
#region [ Comparison Operators ]
///
/// Compares the two values for equality.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A as the result of the operation.
public static bool operator ==(Temperature value1, Temperature value2)
{
return value1.Equals(value2);
}
///
/// Compares the two values for inequality.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A as the result of the operation.
public static bool operator !=(Temperature value1, Temperature value2)
{
return !value1.Equals(value2);
}
///
/// Returns true if left value is less than right value.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A as the result of the operation.
public static bool operator <(Temperature value1, Temperature value2)
{
return value1.CompareTo(value2) < 0;
}
///
/// Returns true if left value is less or equal to than right value.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A as the result of the operation.
public static bool operator <=(Temperature value1, Temperature value2)
{
return value1.CompareTo(value2) <= 0;
}
///
/// Returns true if left value is greater than right value.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A as the result of the operation.
public static bool operator >(Temperature value1, Temperature value2)
{
return value1.CompareTo(value2) > 0;
}
///
/// Returns true if left value is greater than or equal to right value.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A as the result of the operation.
public static bool operator >=(Temperature value1, Temperature value2)
{
return value1.CompareTo(value2) >= 0;
}
#endregion
#region [ Type Conversion Operators ]
///
/// Implicitly converts value, represented in Kelvin, to a .
///
/// A value.
/// A object.
public static implicit operator Temperature(double value)
{
return new Temperature(value);
}
///
/// Implicitly converts , represented in Kelvin, to a .
///
/// A object.
/// A value.
public static implicit operator double(Temperature value)
{
return value.m_value;
}
#endregion
#region [ Arithmetic Operators ]
///
/// Returns computed remainder after dividing first value by the second.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A object as the result of the operation.
public static Temperature operator %(Temperature value1, Temperature value2)
{
return value1.m_value % value2.m_value;
}
///
/// Returns computed sum of values.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A object as the result of the operation.
public static Temperature operator +(Temperature value1, Temperature value2)
{
return value1.m_value + value2.m_value;
}
///
/// Returns computed difference of values.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A object as the result of the operation.
public static Temperature operator -(Temperature value1, Temperature value2)
{
return value1.m_value - value2.m_value;
}
///
/// Returns computed product of values.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A object as the result of the operation.
public static Temperature operator *(Temperature value1, Temperature value2)
{
return value1.m_value * value2.m_value;
}
///
/// Returns computed division of values.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A object as the result of the operation.
public static Temperature operator /(Temperature value1, Temperature value2)
{
return value1.m_value / value2.m_value;
}
// C# doesn't expose an exponent operator but some other .NET languages do,
// so we expose the operator via its native special IL function name
///
/// Returns result of first value raised to power of second value.
///
/// A object as the left hand operand.
/// A object as the right hand operand.
/// A value as the result of the operation.
[EditorBrowsable(EditorBrowsableState.Advanced), SpecialName]
public static double op_Exponent(Temperature value1, Temperature value2)
{
return Math.Pow(value1.m_value, value2.m_value);
}
#endregion
#endregion
#region [ Static ]
// Static Fields
/// Represents the largest possible value of a . This field is constant.
public static readonly Temperature MaxValue = double.MaxValue;
/// Represents the smallest possible value of a . This field is constant.
public static readonly Temperature MinValue = double.MinValue;
// Static Methods
///
/// Creates a new value from the specified in Celsius.
///
/// New value in Celsius.
/// New object from the specified in Celsius.
public static Temperature FromCelsius(double value)
{
return FromTemperature(value, CelsiusFactor, CelsiusOffset, CelsiusStep);
}
///
/// Creates a new value from the specified in Fahrenheit.
///
/// New value in Fahrenheit.
/// New object from the specified in Fahrenheit.
public static Temperature FromFahrenheit(double value)
{
return FromTemperature(value, FahrenheitFactor, FahrenheitOffset, FahrenheitStep);
}
///
/// Creates a new value from the specified in Newton.
///
/// New value in Newton.
/// New object from the specified in Newton.
public static Temperature FromNewton(double value)
{
return FromTemperature(value, NewtonFactor, NewtonOffset, NewtonStep);
}
///
/// Creates a new value from the specified in Rankine.
///
/// New value in Rankine.
/// New object from the specified in Rankine.
public static Temperature FromRankine(double value)
{
return FromTemperature(value, RankineFactor, RankineOffset, RankineStep);
}
///
/// Creates a new value from the specified in Delisle.
///
/// New value in Delisle.
/// New object from the specified in Delisle.
public static Temperature FromDelisle(double value)
{
return FromTemperature(value, DelisleFactor, DelisleOffset, DelisleStep);
}
///
/// Creates a new value from the specified in Réaumur.
///
/// New value in Réaumur.
/// New object from the specified in Réaumur.
public static Temperature FromRéaumur(double value)
{
return FromTemperature(value, RéaumurFactor, RéaumurOffset, RéaumurStep);
}
///
/// Creates a new value from the specified in Rømer.
///
/// New value in Rømer.
/// New object from the specified in Rømer.
public static Temperature FromRømer(double value)
{
return FromTemperature(value, RømerFactor, RømerOffset, RømerStep);
}
///
/// Converts the in the specified to a new in Kelvin.
///
/// Source value.
/// Source value units.
/// New from the specified in .
public static Temperature ConvertFrom(double value, TemperatureUnit sourceUnit)
{
switch (sourceUnit)
{
case TemperatureUnit.Kelvin:
return value;
case TemperatureUnit.Celsius:
return FromCelsius(value);
case TemperatureUnit.Fahrenheit:
return FromFahrenheit(value);
case TemperatureUnit.Newton:
return FromNewton(value);
case TemperatureUnit.Rankine:
return FromRankine(value);
case TemperatureUnit.Delisle:
return FromDelisle(value);
case TemperatureUnit.Réaumur:
return FromRéaumur(value);
case TemperatureUnit.Rømer:
return FromRømer(value);
default:
throw new ArgumentOutOfRangeException(nameof(sourceUnit), sourceUnit, null);
}
}
// Calculate temperature based on K = (value + step) * factor + offset
[MethodImpl(MethodImplOptions.AggressiveInlining)]
private static Temperature FromTemperature(double value, double factor, double offset, double step)
{
return new Temperature((value + step) * factor + offset);
}
#endregion
}
}