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 (&epsilon;&sup2;). The eccentricity
195         * is related to axis length by &epsilon;=√(1-(<var>b</var>/<var>a</var>)&sup2;). 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>,&lt;<var>z</var>&gt;,…) 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    }