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 import java.text.NumberFormat;
033 import java.text.ParseException;
034
035 /**
036 * Extent of something along its greatest dimension or the extent of space
037 * between two objects or places. The metric system unit for this quantity is
038 * "m" (metre).
039 *
040 * @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
041 * @version 1.2
042 * @since 1.0
043 */
044 public final class Length
045 extends Number
046 implements
047 Comparable<Length>,
048 Serializable
049 {
050
051 @Serial
052 private static final long serialVersionUID = 2L;
053
054 /**
055 * Represents a given length unit.
056 */
057 public enum Unit {
058
059 /**
060 * Represents a meter.
061 */
062 METER(1.0),
063
064 /**
065 * Represents a kilometer: ≙ 1,000 m.
066 */
067 KILOMETER(1_000.0),
068
069 /**
070 * Represents an inch: ≙ 0.0254 m.
071 */
072 INCH(127.0/5_000.0),
073
074 /**
075 * Represents a foot: ≙ 0.3048 m.
076 */
077 FOOT(0.3048),
078
079 /**
080 * Represents a yard: ≙ 0.9144 m.
081 */
082 YARD(1_143.0/1_250.0),
083
084 /**
085 * Represents a statute mile: ≙ 1,609.344 m.
086 */
087 MILE(201_168.0/125.0),
088
089 /**
090 * Represents a fathom: ≙ 1.853184 m.
091 */
092 FATHOM(1.853184),
093
094 /**
095 * Represents a cable: ≙ 185.3184 m.
096 */
097 CABLE(185.3184),
098
099 /**
100 * Represents a nautical mile: ≙ 1,853.184 m.
101 */
102 NAUTICAL_MILE(1_853.184);
103
104 private final double _factor;
105
106 Unit(final double factor) {
107 _factor = factor;
108 }
109
110 /**
111 * Convert the given length value of the given {@code sourceUnit} into a
112 * length value of {@code this} length unit. The given example converts 3
113 * inches into yards.
114 *
115 * <pre>{@code
116 * final double yards = YARD.convert(3, INCH);
117 * }</pre>
118 *
119 * @param length the length value
120 * @param sourceUnit the source length unit
121 * @return the speed value of {@code this} length unit
122 */
123 public double convert(final double length, final Unit sourceUnit) {
124 requireNonNull(sourceUnit);
125
126 if (this == sourceUnit) {
127 return length;
128 } else {
129 final double meters = length*sourceUnit._factor;
130 return meters/_factor;
131 }
132 }
133 }
134
135 private final double _value;
136
137 /**
138 * Create a new {@code Length} object with the given value in meters.
139 *
140 * @param value the value (in meters) of the new {@code Length} object
141 */
142 private Length(final double value) {
143 _value = value;
144 }
145
146 /**
147 * Return the length in meter.
148 *
149 * @return the length in meter
150 */
151 @Override
152 public double doubleValue() {
153 return _value;
154 }
155
156 /**
157 * Return the length in the desired unit.
158 *
159 * @param unit the desired length unit
160 * @return the length in the desired unit
161 * @throws NullPointerException if the given length {@code unit} is
162 * {@code null}
163 */
164 public double to(final Unit unit) {
165 return unit.convert(_value, Unit.METER);
166 }
167
168 @Override
169 public int intValue() {
170 return (int)doubleValue();
171 }
172
173 @Override
174 public long longValue() {
175 return (long)doubleValue();
176 }
177
178 @Override
179 public float floatValue() {
180 return (float)doubleValue();
181 }
182
183 @Override
184 public int compareTo(final Length other) {
185 return Double.compare(_value, other._value);
186 }
187
188 @Override
189 public int hashCode() {
190 return Double.hashCode(_value);
191 }
192
193 @Override
194 public boolean equals(final Object obj) {
195 return obj == this ||
196 obj instanceof Length &&
197 Double.compare(((Length)obj)._value, _value) == 0;
198 }
199
200 @Override
201 public String toString() {
202 return format("%s m", _value);
203 }
204
205
206 /* *************************************************************************
207 * Static object creation methods
208 * ************************************************************************/
209
210 /**
211 * Create a new {@code Length} object with the given length.
212 *
213 * @param length the length
214 * @param unit the length unit
215 * @return a new {@code Length} object with the given length.
216 * @throws NullPointerException if the given length {@code unit} is
217 * {@code null}
218 */
219 public static Length of(final double length, final Unit unit) {
220 requireNonNull(unit);
221 return new Length(Unit.METER.convert(length, unit));
222 }
223
224 static Length parse(final String value, final NumberFormat format) {
225 final Double length = parseDouble(value, format);
226 return length != null ? Length.of(length, Unit.METER) : null;
227 }
228
229 private static Double parseDouble(
230 final String value,
231 final NumberFormat format
232 ) {
233 final String length = Strings.trim(value);
234
235 if (length != null) {
236 try {
237 return format.parse(length).doubleValue();
238 } catch (ParseException e) {
239 throw new NumberFormatException("Unable to parse " + value);
240 }
241 } else {
242 return null;
243 }
244 }
245
246 /* *************************************************************************
247 * Java object serialization
248 * ************************************************************************/
249
250 @Serial
251 private Object writeReplace() {
252 return new SerialProxy(SerialProxy.LENGTH, this);
253 }
254
255 @Serial
256 private void readObject(final ObjectInputStream stream)
257 throws InvalidObjectException
258 {
259 throw new InvalidObjectException("Serialization proxy required.");
260 }
261
262 void write(final DataOutput out) throws IOException {
263 out.writeDouble(_value);
264 }
265
266 static Length read(final DataInput in) throws IOException {
267 return new Length(in.readDouble());
268 }
269
270 }
|