001 /*
002 * GeoAPI - Java interfaces for OGC/ISO standards
003 * http://www.geoapi.org
004 *
005 * This file is hereby placed into the Public Domain.
006 * This means anyone is free to do whatever they wish with this file.
007 *
008 * The Proj.4 wrappers are provided as code examples, in the hope to facilitate
009 * GeoAPI implementations backed by other libraries. Implementors can take this
010 * source code and use it for any purpose, commercial or non-commercial, copyrighted
011 * or open-source, with no legal obligation to acknowledge the borrowing/copying
012 * in any way.
013 *
014 * A copy of this file is given to the Proj.4 project under their own Open Source license.
015 * Because the "org.proj4" namespace is the property of the Proj.4 project, change to this
016 * file shall be made in collaboration with the Proj.4 project.
017 */
018 package org.proj4;
019
020
021 /**
022 * Wraps the <a href="http://proj.osgeo.org/">Proj4</a> {@code PJ} native data structure.
023 * Almost every methods defined in this class are native methods delegating the work to the
024 * Proj.4 library. This class is the only place where such native methods are defined.
025 *
026 * <p>In the Proj.4 library, the {@code PJ} structure aggregates in a single place information usually
027 * splitted in many different ISO 19111 interfaces: {@link org.opengis.referencing.datum.Ellipsoid},
028 * {@link org.opengis.referencing.datum.Datum}, {@link org.opengis.referencing.datum.PrimeMeridian},
029 * {@link org.opengis.referencing.cs.CoordinateSystem}, {@link org.opengis.referencing.crs.CoordinateReferenceSystem}
030 * and their sub-interfaces. The relationship with the GeoAPI methods is indicated in the
031 * "See" tags when appropriate.</p>
032 *
033 * @author Martin Desruisseaux (Geomatys)
034 * @version 3.1
035 * @since 3.1
036 */
037 public class PJ {
038 /**
039 * The maximal number of dimension accepted by the {@link #transform(PJ, int, double[], int, int)}
040 * method. This upper limit is actually somewhat arbitrary. This limit exists mostly as a safety
041 * against potential misuse.
042 */
043 public static final int DIMENSION_MAX = 100;
044 // IMPLEMENTATION NOTE: if the value is modified, edit also the native C file.
045
046 /**
047 * Loads the Proj4 library.
048 */
049 static {
050 System.loadLibrary("proj");
051 }
052
053 /**
054 * The pointer to {@code PJ} structure allocated in the C/C++ heap. This value has no
055 * meaning in Java code. <strong>Do not modify</strong>, since this value is used by Proj4.
056 * Do not rename neither, unless you update accordingly the C code in JNI wrappers.
057 */
058 private final long ptr;
059
060 /**
061 * Creates a new {@code PJ} structure from the given Proj4 definition string.
062 *
063 * @param definition The Proj.4 definition string.
064 * @throws IllegalArgumentException If the PJ structure can not be created from the given string.
065 */
066 public PJ(final String definition) throws IllegalArgumentException {
067 ptr = allocatePJ(definition);
068 if (ptr == 0) {
069 throw new IllegalArgumentException(definition);
070 }
071 }
072
073 /**
074 * Creates a new {@code PJ} structure derived from an existing {@code PJ} object.
075 * This constructor is usually for getting the
076 * {@linkplain org.opengis.referencing.crs.ProjectedCRS#getBaseCRS() base geographic CRS}
077 * from a {@linkplain org.opengis.referencing.crs.ProjectedCRS projected CRS}.
078 *
079 * @param crs The CRS (usually projected) from which to derive a new CRS.
080 * @param type The type of the new CRS. Currently, only {@link Type#GEOGRAPHIC} is supported.
081 * @throws IllegalArgumentException If the PJ structure can not be created.
082 */
083 public PJ(final PJ crs, final Type type) throws IllegalArgumentException {
084 if (crs == null) {
085 // TODO: Use Objects with JDK 7.
086 throw new NullPointerException("The CRS must be non-null.");
087 }
088 if (type != Type.GEOGRAPHIC) {
089 throw new IllegalArgumentException("Can not derive the " + type + " type.");
090 }
091 ptr = allocateGeoPJ(crs);
092 if (ptr == 0) {
093 throw new IllegalArgumentException(crs.getLastError());
094 }
095 }
096
097 /**
098 * Allocates a PJ native data structure and returns the pointer to it. This method should be
099 * invoked by the constructor only, and the return value <strong>must</strong> be assigned
100 * to the {@link #ptr} field. The allocated structure is released by the {@link #finalize()}
101 * method.
102 *
103 * @param definition The Proj4 definition string.
104 * @return A pointer to the PJ native data structure, or 0 if the operation failed.
105 */
106 private static native long allocatePJ(String definition);
107
108 /**
109 * Allocates a PJ native data structure for the base geographic CRS of the given CRS, and
110 * returns the pointer to it. This method should be invoked by the constructor only, and
111 * the return value <strong>must</strong> be assigned to the {@link #ptr} field.
112 * The allocated structure is released by the {@link #finalize()} method.
113 *
114 * @param projected The CRS from which to derive the base geographic CRS.
115 * @return A pointer to the PJ native data structure, or 0 if the operation failed.
116 */
117 private static native long allocateGeoPJ(PJ projected);
118
119 /**
120 * Returns the version number of the Proj4 library.
121 *
122 * @return The Proj.4 release string.
123 */
124 public static native String getVersion();
125
126 /**
127 * Returns the Proj4 definition string. This is the string given to the constructor,
128 * expanded with as much information as possible.
129 *
130 * @return The Proj4 definition string.
131 */
132 public native String getDefinition();
133
134 /**
135 * Returns the Coordinate Reference System type.
136 *
137 * @return The CRS type.
138 */
139 public native Type getType();
140
141 /**
142 * The coordinate reference system (CRS) type returned by {@link PJ#getType()}.
143 * In the Proj.4 library, a CRS can only be geographic, geocentric or projected,
144 * without distinction between 2D and 3D CRS.
145 *
146 * @author Martin Desruisseaux (Geomatys)
147 * @version 3.1
148 * @since 3.1
149 */
150 public static enum Type {
151 /*
152 * IMPLEMENTATION NOTE: Do not rename those fields, unless you update the
153 * native C code accordingly.
154 */
155
156 /**
157 * The CRS is of type {@link org.opengis.referencing.crs.GeographicCRS}.
158 * The CRS can be two-dimensional or three-dimensional.
159 */
160 GEOGRAPHIC,
161
162 /**
163 * The CRS is of type {@link org.opengis.referencing.crs.GeocentricCRS}.
164 * The CRS can only be three-dimensional.
165 */
166 GEOCENTRIC,
167
168 /**
169 * The CRS is of type {@link org.opengis.referencing.crs.ProjectedCRS}.
170 * The CRS can be two-dimensional or three-dimensional.
171 */
172 PROJECTED
173 }
174
175 /**
176 * Returns the value stored in the {@code a_orig} PJ field.
177 *
178 * @return The axis length stored in {@code a_orig}.
179 *
180 * @see org.opengis.referencing.datum.Ellipsoid#getSemiMajorAxis()
181 */
182 public native double getSemiMajorAxis();
183
184 /**
185 * Returns the value computed from PJ fields by {@code √((a_orig)² × (1 - es_orig))}.
186 *
187 * @return The axis length computed by {@code √((a_orig)² × (1 - es_orig))}.
188 *
189 * @see org.opengis.referencing.datum.Ellipsoid#getSemiMinorAxis()
190 */
191 public native double getSemiMinorAxis();
192
193 /**
194 * Returns the square of the ellipsoid eccentricity (ε²). The eccentricity
195 * is related to axis length by ε=√(1-(<var>b</var>/<var>a</var>)²). The
196 * eccentricity of a sphere is zero.
197 *
198 * @return The eccentricity.
199 *
200 * @see org.opengis.referencing.datum.Ellipsoid#isSphere()
201 * @see org.opengis.referencing.datum.Ellipsoid#getInverseFlattening()
202 */
203 public native double getEccentricitySquared();
204
205 /**
206 * Returns an array of character indicating the direction of each axis. Directions are
207 * characters like {@code 'e'} for East, {@code 'n'} for North and {@code 'u'} for Up.
208 *
209 * @return The axis directions.
210 *
211 * @see org.opengis.referencing.cs.CoordinateSystemAxis#getDirection()
212 */
213 public native char[] getAxisDirections();
214
215 /**
216 * Longitude of the prime meridian measured from the Greenwich meridian, positive eastward.
217 *
218 * @return The prime meridian longitude, in degrees.
219 *
220 * @see org.opengis.referencing.datum.PrimeMeridian#getGreenwichLongitude()
221 */
222 public native double getGreenwichLongitude();
223
224 /**
225 * Returns the conversion factor from the linear units to metres.
226 *
227 * @param vertical {@code false} for the conversion factor of horizontal axes,
228 * or {@code true} for the conversion factor of the vertical axis.
229 * @return The conversion factor to metres for the given axis.
230 */
231 public native double getLinearUnitToMetre(boolean vertical);
232
233 /**
234 * Transforms in-place the coordinates in the given array. The coordinates array shall contain
235 * (<var>x</var>,<var>y</var>,<var>z</var>,…) tuples, where the <var>z</var> and
236 * following dimensions are optional. Note that any dimension after the <var>z</var> value
237 * are ignored.
238 *
239 * <p>Input and output units:</p>
240 * <ul>
241 * <li>Angular units (as in longitude and latitudes) are decimal degrees.</li>
242 * <li>Linear units are usually metres, but this is actually projection-dependent.</li>
243 * </ul>
244 *
245 * @param target The target CRS.
246 * @param dimension The dimension of each coordinate value. Must be in the [2-{@value #DIMENSION_MAX}] range.
247 * @param coordinates The coordinates to transform, as a sequence of
248 * (<var>x</var>,<var>y</var>,<<var>z</var>>,…) tuples.
249 * @param offset Offset of the first coordinate in the given array.
250 * @param numPts Number of points to transform.
251 * @throws NullPointerException If the {@code target} or {@code coordinates} argument is null.
252 * @throws IndexOutOfBoundsException if the {@code offset} or {@code numPts} arguments are invalid.
253 * @throws PJException If the operation failed for an other reason (provided by Proj4).
254 *
255 * @see org.opengis.referencing.operation.MathTransform#transform(double[], int, double[], int, int)
256 */
257 public native void transform(PJ target, int dimension, double[] coordinates, int offset, int numPts)
258 throws PJException;
259
260 /**
261 * Returns a description of the last error that occurred, or {@code null} if none.
262 *
263 * @return The last error that occurred, or {@code null}.
264 */
265 public native String getLastError();
266
267 /**
268 * Returns the string representation of the PJ structure.
269 *
270 * @return The string representation.
271 */
272 @Override
273 public native String toString();
274
275 /**
276 * Deallocates the native PJ data structure. This method can be invoked only by the garbage
277 * collector, and must be invoked exactly once (no more, no less).
278 * <strong>NEVER INVOKE THIS METHOD EXPLICITELY, NEVER OVERRIDE</strong>.
279 */
280 @Override
281 protected final native void finalize();
282 }