View Javadoc
1   package org.djunits.unit.scale;
2   
3   /**
4    * Scale with factor and zero point offset.
5    * <p>
6    * A Scale for linear transformations with an offset that has to be applied first when converting to the standard (SI) unit,
7    * before the scaling takes place, e.g. for Temperature. As an example, transform from Degrees Fahrenheit to Kelvin (SI). The
8    * conversion is K = (F + 459.67) × 5⁄9, and F = K × 9⁄5 − 459.67.
9    * </p>
10   * <p>
11   * When we have an original scale with offset o1 and scalefactor f1, the calculation to the base unit is
12   * 
13   * <pre>
14   * valueSI = (value1 + o1) * f1
15   * </pre>
16   * <p>
17   * So the offset is expressed in the "unit" of the value. As an example, when we transform degrees Fahrenheit to Kelvin, the
18   * factor is 5/9, and the offset is 459.67 (degrees Fahrenheit of 0 degrees Fahrenheit expressed in Kelvin). The formula
19   * becomes: K = (F + 459.67) * 5/9. So 0 F is 459.67 * 5/9 = 255.372 K. For Celcius to Kelvin, the scale factor is 1, and the
20   * offset 273.15. From Fahrenheit to Celcius, the offset is -32, and the factor is 5/9.
21   * </p>
22   * <p>
23   * When we apply a second offset transformation on a scale, e.g. from Fahrenheit to Celcius to Kelvin, this works as follows: If
24   * we combine a second scale factor for a derived unit with offset o2 and scalefactor f2, we need to calculate the ultimate
25   * scale to the base (si) unit. The factor then becomes:
26   * 
27   * <pre>
28   * value1  = (value2 + o2) * f2
29   * valueSI = (value1 + o1) * f1 = value2 * (f1 * f2) + (f1 * f2 * o2 + f1 * o1)
30   * </pre>
31   * <p>
32   * as an example for F --2--&gt; C --1--&gt; K: o1 = 273.15, f1 = 1, o2 = -32, f2 = 5/9: <br>
33   * 110 F = 110*5/9 -32*5/9 + 273.15 = 316.483 K.
34   * </p>
35   * <p>
36   * Copyright (c) 2013-2024 Delft University of Technology, PO Box 5, 2600 AA, Delft, the Netherlands. All rights reserved. <br>
37   * BSD-style license. See <a href="https://djunits.org/docs/license.html">DJUNITS License</a>.
38   * </p>
39   * @author <a href="https://www.tudelft.nl/averbraeck">Alexander Verbraeck</a>
40   * @author <a href="https://www.tudelft.nl/staff/p.knoppers/">Peter Knoppers</a>
41   */
42  public class OffsetLinearScale extends LinearScale
43  {
44      /** */
45      private static final long serialVersionUID = 20151011L;
46  
47      /** The offset that has to be taken into account for conversions, multiplied by the conversionFactorToStandardUnit. */
48      private final double offsetToStandardUnit;
49  
50      /**
51       * Construct a Scale for linear transformations with an offset, e.g. for Temperature.
52       * @param conversionFactorToStandardUnit double; the conversion factor by which this number has to be multiplied to convert
53       *            it to the standard (e.g., SI) unit.
54       * @param offsetToStandardUnit the offset that has to be taken into account for conversions; when converting to a standard
55       *            unit, the offset is applied first.
56       */
57      public OffsetLinearScale(final double conversionFactorToStandardUnit, final double offsetToStandardUnit)
58      {
59          super(conversionFactorToStandardUnit);
60          this.offsetToStandardUnit = offsetToStandardUnit;
61      }
62  
63      @Override
64      public final double toStandardUnit(final double value)
65      {
66          return (value + this.offsetToStandardUnit) * getConversionFactorToStandardUnit();
67      }
68  
69      @Override
70      public final double fromStandardUnit(final double value)
71      {
72          return value / getConversionFactorToStandardUnit() - this.offsetToStandardUnit;
73      }
74  
75      /**
76       * Retrieve the offset from the standard unit.
77       * @return double; the offset from the standard unit
78       */
79      public final double getOffsetToStandardUnit()
80      {
81          return this.offsetToStandardUnit;
82      }
83  
84      @Override
85      public boolean isBaseSIScale()
86      {
87          return super.isBaseSIScale() && this.offsetToStandardUnit == 0.0;
88      }
89  
90      @Override
91      public int hashCode()
92      {
93          final int prime = 31;
94          int result = super.hashCode();
95          long temp;
96          temp = Double.doubleToLongBits(this.offsetToStandardUnit);
97          result = prime * result + (int) (temp ^ (temp >>> 32));
98          return result;
99      }
100 
101     @SuppressWarnings("checkstyle:needbraces")
102     @Override
103     public boolean equals(final Object obj)
104     {
105         if (this == obj)
106             return true;
107         if (!super.equals(obj))
108             return false;
109         if (getClass() != obj.getClass())
110             return false;
111         OffsetLinearScale other = (OffsetLinearScale) obj;
112         if (Double.doubleToLongBits(this.offsetToStandardUnit) != Double.doubleToLongBits(other.offsetToStandardUnit))
113             return false;
114         return true;
115     }
116 
117     @Override
118     public String toString()
119     {
120         return "OffsetLinearScale [offsetToStandardUnit=" + this.offsetToStandardUnit + ", conversionFactorToStandardUnit="
121                 + this.getConversionFactorToStandardUnit() + "]";
122     }
123 
124 }