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 */ 020package io.jenetics.jpx; 021 022import static java.lang.String.format; 023import static java.util.Objects.requireNonNull; 024 025import java.io.DataInput; 026import java.io.DataOutput; 027import java.io.IOException; 028import java.io.InvalidObjectException; 029import java.io.ObjectInputStream; 030import java.io.Serial; 031import 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 */ 040public 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 out) throws IOException { 223 out.writeDouble(_value); 224 } 225 226 static Speed read(final DataInput in) throws IOException { 227 return new Speed(in.readDouble()); 228 } 229 230}