Speed.java
001 /*
002  * Java GPX Library (jpx-3.1.0).
003  * Copyright (c) 2016-2023 Franz Wilhelmstötter
004  *
005  * Licensed under the Apache License, Version 2.0 (the "License");
006  * you may not use this file except in compliance with the License.
007  * You may obtain a copy of the License at
008  *
009  *      http://www.apache.org/licenses/LICENSE-2.0
010  *
011  * Unless required by applicable law or agreed to in writing, software
012  * distributed under the License is distributed on an "AS IS" BASIS,
013  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014  * See the License for the specific language governing permissions and
015  * limitations under the License.
016  *
017  * Author:
018  *    Franz Wilhelmstötter (franz.wilhelmstoetter@gmail.com)
019  */
020 package io.jenetics.jpx;
021 
022 import static java.lang.String.format;
023 import static java.util.Objects.requireNonNull;
024 
025 import java.io.DataInput;
026 import java.io.DataOutput;
027 import java.io.IOException;
028 import java.io.InvalidObjectException;
029 import java.io.ObjectInputStream;
030 import java.io.Serial;
031 import java.io.Serializable;
032 
033 /**
034  * Represents the GPS speed value in m/s.
035  *
036  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
037  @version 1.2
038  @since 1.0
039  */
040 public final class Speed
041     extends Number
042     implements
043         Comparable<Speed>,
044         Serializable
045 {
046 
047     @Serial
048     private static final long serialVersionUID = 2L;
049 
050     /**
051      * Represents a given speed unit.
052      */
053     public enum Unit {
054 
055         /**
056          * Represents the speed unit <em>meters per second</em><b>m/s</b>.
057          */
058         METERS_PER_SECOND(1.0),
059 
060         /**
061          * Represents the speed unit <em>kilometers per hour</em><b>km/h</b>.
062          */
063         KILOMETERS_PER_HOUR(5.0/18.0),
064 
065         /**
066          * Represents the speed unit <em>miles per hour</em><b>mi/h</b>.
067          */
068         MILES_PER_HOUR(1_397.0/3_125.0),
069 
070         /**
071          * Represents the speed unit <em>knots</em><b>kt</b>.
072          */
073         KNOTS(463.0/900.0),
074 
075         /**
076          * Represents the speed unit <em>mach</em><b>Ma</b>.
077          */
078         MACH(331.3);
079 
080         // The conversion factor to the base unit m/s.
081         private final double _factor;
082 
083         Unit(final double factor) {
084             _factor = factor;
085         }
086 
087         /**
088          * Convert the given speed value of the given {@code sourceUnit} into a
089          * speed value of {@code this} speed unit. The given example converts 3
090          * knots into kilometers per hour.
091          *
092          <pre>{@code
093          * final double kilometersPerHour = KILOMETERS_PER_HOUR.convert(3, KNOTS);
094          * }</pre>
095          *
096          @param speed the speed value
097          @param sourceUnit the source speed unit
098          @return the speed value of {@code this} speed unit
099          */
100         public double convert(final double speed, final Unit sourceUnit) {
101             requireNonNull(sourceUnit);
102             final double metersPerSecond = speed*sourceUnit._factor;
103             return metersPerSecond/_factor;
104         }
105 
106     }
107 
108 
109     private final double _value;
110 
111     /**
112      * Create a new GPS {@code Speed} object in m/s.
113      *
114      @param value the GPS speed value in m/s.
115      */
116     private Speed(final double value) {
117         _value = value;
118     }
119 
120     /**
121      * Return the GPS speed value in m/s.
122      *
123      @return the GPS speed value in m/s
124      */
125     @Override
126     public double doubleValue() {
127         return _value;
128     }
129 
130     /**
131      * Return the GPS speed value in the desired unit.
132      *
133      @param unit the speed unit
134      @return the GPS speed value in the desired unit
135      @throws NullPointerException if the given speed {@code unit} is
136      *         {@code null}
137      */
138     public double to(final Unit unit) {
139         requireNonNull(unit);
140         return unit.convert(_value, Unit.METERS_PER_SECOND);
141     }
142 
143     @Override
144     public int intValue() {
145         return (int)doubleValue();
146     }
147 
148     @Override
149     public long longValue() {
150         return (long)doubleValue();
151     }
152 
153     @Override
154     public float floatValue() {
155         return (float)doubleValue();
156     }
157 
158     @Override
159     public int compareTo(final Speed speed) {
160         return Double.compare(_value, speed._value);
161     }
162 
163     @Override
164     public int hashCode() {
165         return Double.hashCode(_value);
166     }
167 
168     @Override
169     public boolean equals(final Object obj) {
170         return obj == this ||
171             obj instanceof Speed speed &&
172             Double.compare(speed._value, _value== 0;
173     }
174 
175     @Override
176     public String toString() {
177         return format("%s m/s", _value);
178     }
179 
180 
181     /* *************************************************************************
182      *  Static object creation methods
183      * ************************************************************************/
184 
185     /**
186      * Create a new GPS {@code Speed} object.
187      *
188      @param speed the GPS speed value
189      @param unit the speed unit
190      @return a new GPS {@code Speed} object
191      @throws NullPointerException if the given speed {@code unit} is
192      *         {@code null}
193      */
194     public static Speed of(final double speed, final Unit unit) {
195         requireNonNull(unit);
196         return new Speed(Unit.METERS_PER_SECOND.convert(speed, unit));
197     }
198 
199     static Speed parse(final String value) {
200         final String speed = Strings.trim(value);
201         return speed != null
202             ? Speed.of(Double.parseDouble(speed), Unit.METERS_PER_SECOND)
203             null;
204     }
205 
206     /* *************************************************************************
207      *  Java object serialization
208      * ************************************************************************/
209 
210     @Serial
211     private Object writeReplace() {
212         return new SerialProxy(SerialProxy.SPEED, this);
213     }
214 
215     @Serial
216     private void readObject(final ObjectInputStream stream)
217         throws InvalidObjectException
218     {
219         throw new InvalidObjectException("Serialization proxy required.");
220     }
221 
222     void write(final DataOutput outthrows IOException {
223         out.writeDouble(_value);
224     }
225 
226     static Speed read(final DataInput inthrows IOException {
227         return new Speed(in.readDouble());
228     }
229 
230 }