Latitude.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 
024 import java.io.DataInput;
025 import java.io.DataOutput;
026 import java.io.IOException;
027 import java.io.InvalidObjectException;
028 import java.io.ObjectInputStream;
029 import java.io.Serial;
030 import java.io.Serializable;
031 
032 /**
033  * The latitude of the point. Decimal degrees, WGS84 datum, which must be within
034  * the range of {@code [-90..90]}.
035  *
036  @author <a href="mailto:franz.wilhelmstoetter@gmail.com">Franz Wilhelmstötter</a>
037  @version 2.0
038  @since 1.0
039  */
040 public final class Latitude extends Number implements Serializable {
041 
042     @Serial
043     private static final long serialVersionUID = 2L;
044 
045     /**
046      * A constant holding the maximum value a {@code Latitude} value can have,
047      * -90 inclusively.
048      *
049      @since 2.0
050      */
051     public static final double MIN_DEGREES = -90;
052 
053     /**
054      * A constant holding the maximum value a {@code Latitude} value can have,
055      * -90 inclusively.
056      *
057      @since 1.4
058      */
059     public static final Latitude MIN_VALUE = ofDegrees(MIN_DEGREES);
060 
061     /**
062      * A constant holding the maximum value a {@code Latitude} value can have,
063      * 90 inclusively.
064      *
065      @since 2.0
066      */
067     public static final double MAX_DEGREES = 90;
068 
069     /**
070      * A constant holding the maximum value a {@code Latitude} value can have,
071      * 90 inclusively.
072      *
073      @since 1.4
074      */
075     public static final Latitude MAX_VALUE = ofDegrees(MAX_DEGREES);
076 
077     private final double _value;
078 
079     /**
080      * Create a new (decimal degrees) {@code Latitude} value.
081      *
082      @param value the latitude value in decimal degrees
083      @throws IllegalArgumentException if the given value is not within the
084      *         range of {@code [-90..90]}
085      */
086     private Latitude(final double value) {
087         if (value < MIN_DEGREES || value > MAX_DEGREES) {
088             throw new IllegalArgumentException(format(
089                 "%f is not in range [-90, 90].", value
090             ));
091         }
092 
093         _value = value;
094     }
095 
096     /**
097      * Return the latitude value in decimal degrees.
098      *
099      @return the latitude value in decimal degrees
100      */
101     @Override
102     public double doubleValue() {
103         return _value;
104     }
105 
106     /**
107      * Return the latitude value in radians.
108      *
109      @return the latitude value in radians
110      */
111     public double toRadians() {
112         return Math.toRadians(_value);
113     }
114 
115     /**
116      * Return the latitude in decimal degree.
117      *
118      @return the latitude in decimal degree
119      */
120     public double toDegrees() {
121         return _value;
122     }
123 
124     @Override
125     public int intValue() {
126         return (int)doubleValue();
127     }
128 
129     @Override
130     public long longValue() {
131         return (long)doubleValue();
132     }
133 
134     @Override
135     public float floatValue() {
136         return (float)doubleValue();
137     }
138 
139     @Override
140     public int hashCode() {
141         return Double.hashCode(_value);
142     }
143 
144     @Override
145     public boolean equals(final Object obj) {
146         return obj == this ||
147             obj instanceof Latitude lat &&
148             Double.compare(lat._value, _value== 0;
149     }
150 
151     @Override
152     public String toString() {
153         return Double.toString(_value);
154     }
155 
156 
157     /* *************************************************************************
158      *  Static object creation methods
159      * ************************************************************************/
160 
161     /**
162      * Create a new (decimal degrees) {@code Latitude} object.
163      *
164      @param degrees the latitude value in decimal degrees
165      @return a new (decimal degrees) {@code Latitude} object
166      @throws IllegalArgumentException if the given value is not within the
167      *         range of {@code [-90..90]}
168      */
169     public static Latitude ofDegrees(final double degrees) {
170         return new Latitude(degrees);
171     }
172 
173     /**
174      * Create a new {@code Latitude} value for the given {@code radians}.
175      *
176      @param radians the latitude value in radians
177      @return  a new {@code Latitude} value for the given {@code radians}
178      @throws IllegalArgumentException if the given radians is not within the
179      *         range of {@code [-Pi..Pi]}
180      */
181     public static Latitude ofRadians(final double radians) {
182         return new Latitude(Math.toDegrees(radians));
183     }
184 
185     static Latitude parse(final String value) {
186         final String lat = Strings.trim(value);
187         return lat != null
188             ? Latitude.ofDegrees(Double.parseDouble(lat))
189             null;
190     }
191 
192     /* *************************************************************************
193      *  Java object serialization
194      * ************************************************************************/
195 
196     @Serial
197     private Object writeReplace() {
198         return new SerialProxy(SerialProxy.LATITUDE, this);
199     }
200 
201     @Serial
202     private void readObject(final ObjectInputStream stream)
203         throws InvalidObjectException
204     {
205         throw new InvalidObjectException("Serialization proxy required.");
206     }
207 
208     void write(final DataOutput outthrows IOException {
209         out.writeDouble(_value);
210     }
211 
212     static Latitude read(final DataInput inthrows IOException {
213         return new Latitude(in.readDouble());
214     }
215 
216 }