利用导出类调用
http://proj4net.codeplex.com/
C#
Wrapper for native proj4 http://ftp.dfg.ca.gov/Public/BDB/Tools/proj4/
proj_api.cs
/*============================================================================ * AUTHOR: Eric G. Miller * DATE: 2004-09-15 * PURPOSE: * Provide both high-level and low-level interfaces to the PROJ.4 * projection library. This interface was written against a slightly * modified copy of version 4.4.8. Any significant changes were sent to * upstream for incorporation into later versions. * COPYRIGHT: Copyright (c) 2004, 2010 California Department of Fish and Game * LICENSE: MIT Style * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * CHANGES: * For 4.7.0 (2010-01-29, Eric G. Miller) * - Change definition of pj_alloc and pj_dalloc to work with IntPtr's * - Change return values of pj_get_def, pj_strerrno, pj_release to * IntPtr's. Use Marshal.PtrToStringAnsi. Free the IntPtr from pj_get_def * using either pj_dalloc or Marshal.FreeHGlobal. The results from * the other two functions should not be released (static data). * - Add GetErrorMessage and GetErrno helpers to Projection class. * - Removed all unsafe code * - Implemented IDisposable on the Projection class * - Other minor modifications related to the changes noted above. *===========================================================================*/ using System; using System.Runtime.InteropServices; namespace ProjApi { /// <summary> /// Common struct for data points /// </summary> [ StructLayout(LayoutKind.Sequential) ] public struct ProjUV { public double u; public double v; } /// <summary> /// This class thinly wraps proj.4 library functions. Some of it uses /// unsafe code. /// </summary> public class Proj { /// <summary> /// Constants for converting coordinates between radians and degrees /// </summary> public const double RAD_TO_DEG = 57.29577951308232; public const double DEG_TO_RAD = .0174532925199432958; /// <summary> /// The finder function is used by the projection library to locate /// resources like datum shift files and projection configuration /// files. (NOTE: Not functional due to calling convention). /// </summary> public delegate IntPtr FinderFunction([MarshalAs(UnmanagedType.LPStr)] string path); ///// <summary> ///// Pointer to the global error number ///// </summary> //public unsafe static int* pj_errno = pj_get_errno_ref(); /// <summary> /// Perform a forward projection (from lat/long). /// </summary> /// <param name="LP">The lat/long coordinate in radians</param> /// <param name="projPJ">The projection definition</param> /// <returns>The projected coordinate in system units</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern ProjUV pj_fwd(ProjUV LP, IntPtr projPJ); /// <summary> /// Perform an inverse projection (to lat/long). /// </summary> /// <param name="XY">The projected coordinate in system units</param> /// <param name="projPJ">The projection definition</param> /// <returns>The lat/long coordinate in radians</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern ProjUV pj_inv(ProjUV XY, IntPtr projPJ); /// <summary> /// Transform a set of coordinates from one system to another (includes datum transformation) /// </summary> /// <param name="src">Source coordinate system</param> /// <param name="dst">Destination coordinate system</param> /// <param name="point_count">Number of points in the arrays</param> /// <param name="point_offset">Offset to use when iterating through array. Use "1" for /// normal arrays or use "2" or "3" when using a single array for all of the x, y /// and [optional] z elements.</param> /// <param name="x">The "X" coordinate array</param> /// <param name="y">The "Y" coordinate array</param> /// <param name="z">The "Z" coordinate array (may be null)</param> /// <returns>Zero on success, pj_errno on failure</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_transform(IntPtr src, IntPtr dst, int point_count, int point_offset, [InAttribute, OutAttribute] double[] x, [InAttribute, OutAttribute] double[] y, [InAttribute, OutAttribute] double[] z); /// <summary> /// Perform a datum transformation on the inputs. Typically you would use /// pj_transform which calls this function internally. /// </summary> /// <param name="src">Source coordinate system definition</param> /// <param name="dst">Destination coordinate system definition</param> /// <param name="point_count">Count of points in the array(s)</param> /// <param name="point_offset">Offset of each element (see pj_transform)</param> /// <param name="x">Array of "X" values</param> /// <param name="y">Array of "Y" values</param> /// <param name="z">Array of "Z" values (may be null)</param> /// <returns>Zero on success, pj_errno on failure</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_datum_transform(IntPtr src, IntPtr dst, int point_count, int point_offset, [InAttribute, OutAttribute] double[] x, [InAttribute, OutAttribute] double[] y, [InAttribute, OutAttribute] double[] z); /// <summary> /// Convert geocentric coordinates to geodetic. /// </summary> /// <param name="a">Ellipsoid semi-major axis</param> /// <param name="es">Square of ellipsoid eccentricity</param> /// <param name="point_count">Count of points in array(s)</param> /// <param name="point_offset">Offset of each element in array(s) (see pj_transform)</param> /// <param name="x">Array of "X" values</param> /// <param name="y">Array of "Y" values</param> /// <param name="z">Array of "Z" values</param> /// <returns>Zero</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_geocentric_to_geodetic(double a, double es, int point_count, int point_offset, [InAttribute, OutAttribute] double[] x, [InAttribute, OutAttribute] double[] y, [InAttribute, OutAttribute] double[] z); /// <summary> /// Convert geodetic coordinates to geocentric. Called by pj_datum_transform /// if needed. /// </summary> /// <param name="a">Ellipsoid semi-major axis</param> /// <param name="es">Square of ellipsoid eccentricity</param> /// <param name="point_count">Count of points in array(s)</param> /// <param name="point_offset">Offset of each element in array(s) (see pj_transform)</param> /// <param name="x">Array of "X" values</param> /// <param name="y">Array of "Y" values</param> /// <param name="z">Array of "Z" values</param> /// <returns>Zero</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_geodetic_to_geocentric(double a, double es, int point_count, int point_offset, [InAttribute, OutAttribute] double[] x, [InAttribute, OutAttribute] double[] y, [InAttribute, OutAttribute] double[] z); /// <summary> /// Compare the datum definitions in two coordinate system definitions /// for equality. /// </summary> /// <param name="srcdefn">Source coordinate system</param> /// <param name="dstdefn">Destination coordinate system</param> /// <returns>One if true, Zero if false</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_compare_datums(IntPtr srcdefn, IntPtr dstdefn ); /// <summary> /// Apply a gridshift datum transformation on the inputs /// </summary> /// <param name="nadgrids">name of the gridshift file</param> /// <param name="inverse">flag whether shifting to or from</param> /// <param name="point_count">Count of points in the array(s)</param> /// <param name="point_offset">Offset of each element (see pj_transform)</param> /// <param name="x">Array of "X" values</param> /// <param name="y">Array of "Y" values</param> /// <param name="z">Array of "Z" values (may be null)</param> /// <returns>Zero on success, pj_errno on failure</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_apply_gridshift([MarshalAs(UnmanagedType.LPStr)] string nadgrids, int inverse, int point_count, int point_offset, [InAttribute, OutAttribute] double[] x, [InAttribute, OutAttribute] double[] y, [InAttribute, OutAttribute] double[] z); /// <summary> /// Free up any loaded datum grids from memory. /// </summary> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern void pj_deallocate_grids(); /// <summary> /// Is the coordinate system definition lat/long ? /// </summary> /// <param name="projPJ">Coordinate system definition</param> /// <returns>One if true, Zero if false</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_is_latlong(IntPtr projPJ); /// <summary> /// Is the coordinate system definition geocentric? /// </summary> /// <param name="projPJ">Coordinate system definition</param> /// <returns>One if true, Zero if false</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern int pj_is_geocent(IntPtr projPJ); /// <summary> /// Print the coordinate system definition to stdout. /// </summary> /// <param name="projPJ">The coordinate system definition</param> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern void pj_pr_list(IntPtr projPJ); /// <summary> /// Frees the memory allocated for a projection definition. /// Attempting to use the object after calling this function or attempting /// to call this function more than once with the same object will cause /// your application to blow up. /// </summary> /// <param name="projPJ">Opaque pointer to a projection definition (null is okay)</param> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] //public unsafe static extern void pj_free(void* projPJ); public static extern void pj_free(IntPtr projPJ); /// <summary> /// Install a custom function to locate resource files. Once installed, the /// library will use this until uninstalled (set to null), so make sure the /// delegate variable is not garbage collected without "uninstalling" the /// function first. (NOTE: Not useable due to calling convention) /// </summary> /// <param name="f">The function delegate</param> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern void pj_set_finder( [MarshalAs(UnmanagedType.FunctionPtr)] FinderFunction f); /// <summary> /// Initialize a coordinate system definition like a "C" style main function /// loop. /// </summary> /// <param name="argc">Count of elements in argv</param> /// <param name="argv">Array of string parameters</param> /// <returns>Opaque pointer to a coordinate system definition, or null on failure.</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_init(int argc, [MarshalAs(UnmanagedType.LPArray, ArraySubType=UnmanagedType.LPStr, SizeParamIndex=1)] string[] argv); /// <summary> /// Initialize a projection definition object from a string of arguments /// </summary> /// <param name="pjstr">The string of projection arguments</param> /// <returns>Opaque pointer to a projection definition or null on failure</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_init_plus( [MarshalAs(UnmanagedType.LPStr)] string pjstr); /// <summary> /// Get a string representation of the coordinate system definition /// </summary> /// <param name="projPJ">The coordinate system definition</param> /// <param name="options">Unused</param> /// <returns>A string representing the coordinate system definition</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_get_def(IntPtr projPJ, int options); /// <summary> /// Return a coordinate system definition defining the lat/long coordinate */ /// system on which a projection is based. If the coordinate /// system passed in is latlong, a clone of the same will be returned. /// </summary> /// <param name="projPJ">The source coordinate system definition</param> /// <returns>The lat/long coordinate system definition</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_latlong_from_proj(IntPtr projPJ); /// <summary> /// Allocate a chunk of memory using malloc. /// </summary> /// <param name="size">The size of the memory chunk to allocate</param> /// <returns>A pointer to the allocated memory, or null on failure.</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_malloc(uint size); /// <summary> /// Deallocate a chunk of memory previously allocated with pj_alloc (malloc). /// </summary> /// <param name="memory">The pointer to the chunk of memory to free.</param> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern void pj_dalloc(IntPtr memory); /// <summary> /// Get the string value corresponding to the error number. /// </summary> /// <param name="errno">The error number</param> /// <returns>The error message</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_strerrno(int errno); /// <summary> /// Get a pointer to the int holding the last error number /// </summary> /// <returns>pointer to the error number variable</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_get_errno_ref(); /// <summary> /// Get the PROJ.4 library release string /// </summary> /// <returns>string containing library release version</returns> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern IntPtr pj_get_release(); /// <summary> /// Specifies directories in which the projection library should look for /// resource files. /// </summary> /// <param name="count">number of elements in the array</param> /// <param name="path">array of strings specifying directories to look for files in.</param> [DllImport("proj.dll", CharSet=CharSet.Ansi, CallingConvention=CallingConvention.Cdecl)] public static extern void pj_set_searchpath(int count, string[] path ); } /// <summary> /// This class is a thicker interface to the PROJ.4 library. It exposes a small /// set of methods, but generally these are all that is needed. /// </summary> public class Projection : IDisposable { // INTERNAL data /// <summary> /// The pointer to the projection definition object /// </summary> internal IntPtr prj = IntPtr.Zero; /// <summary> /// Cache of the definition string returned by pj_get_def /// </summary> internal string out_def = null; /// <summary> /// Common object initialization function /// </summary> /// <param name="definition">The projection definition string</param> /// <exception cref="System.ArgumentException">Thrown when initialization fails. /// The reason may vary and will be documented in the Message</exception> private void Initialize(string definition) { IntPtr thePrj = Proj.pj_init_plus(definition); if (thePrj == IntPtr.Zero) { string message = GetErrorMessage(GetErrNo()); throw new System.ArgumentException(message); } this.prj = thePrj; this.out_def = null; } /// <summary> /// Read the current pj_errno value. /// </summary> /// <returns>The current pj_errno value.</returns> public static int GetErrNo() { int errno = 0; IntPtr pErrNo = Proj.pj_get_errno_ref(); errno = Marshal.ReadInt32(pErrNo); return errno; } /// <summary> /// Get the error message corresponding to /// the errno /// </summary> /// <param name="errno">The error number</param> /// <returns>The message, or null if errno == 0</returns> public static string GetErrorMessage(int errno) { if (errno == 0) return null; IntPtr pMsg = Proj.pj_strerrno(errno); return Marshal.PtrToStringAnsi(pMsg); } /// <summary> /// Instance version checks initialization status. /// </summary> private void CheckInitialized() { Projection.CheckInitialized(this); } /// <summary> /// Static version that checks initialization status. /// </summary> /// <param name="p">The projection object</param> private static void CheckInitialized(Projection p) { if (p.prj == IntPtr.Zero) { throw new ApplicationException("Projection not initialized"); } } /// <summary> /// The default constructor /// </summary> public Projection() {} /// <summary> /// Constructor with a definition /// </summary> /// <param name="paramaters">string defining the coordinate system</param> public Projection(string definition) : base() { this.Initialize(definition); } // PROPERTIES /// <summary> /// A string representing the coordinate system. Setting it [re]initializes the /// projection definition. /// </summary> /// <exception cref="System.ArgumentException">Thrown when initialization fails (set). /// The reason may vary and will be documented in the Message</exception> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized (get).</exception> public string Definition { set { this.Initialize(value); } get { this.CheckInitialized(); if (this.out_def == null) { IntPtr pDef = Proj.pj_get_def(this.prj, 0); this.out_def = Marshal.PtrToStringAnsi(pDef); Proj.pj_dalloc(pDef); } return this.out_def; } } /// <summary> /// Returns true if the projection definition is Lat/Long. /// </summary> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized (get).</exception> public bool IsLatLong { get { this.CheckInitialized(); return (Proj.pj_is_latlong(this.prj) == 0) ? false : true; } } /// <summary> /// Returns true if the projection definition is Geocentric (XYZ) /// </summary> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized (get).</exception> public bool IsGeoCentric { get { this.CheckInitialized(); return (Proj.pj_is_geocent(this.prj) == 0) ? false : true; } } // METHODS /// <summary> /// Get a projection object with the underlying /// Lat/Long definition /// </summary> /// <returns>Projection</returns> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized.</exception> /// <exception cref="System.ArgumentException">Thrown when the underlying library /// does not return a valid Lat/Long projection object. This might happen if the /// original projection does not have an underlying Lat/Long coordinate system. /// </exception> public Projection GetLatLong() { this.CheckInitialized(); Projection new_prj = new Projection(); new_prj.prj = Proj.pj_latlong_from_proj(this.prj); if (new_prj.prj == IntPtr.Zero) { string message = GetErrorMessage(GetErrNo()); throw new System.ArgumentException(message); } return new_prj; } /// <summary> /// Returns the projection definition string (Same as .Definition property) /// </summary> /// <returns>Projection definition string</returns> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized.</exception> public override string ToString() { return this.Definition; } /// <summary> /// Sets search directories for the PROJ.4 library to look for its resource /// files (such as datum grid files, state plane files, etc...). Search /// paths are only used if other means fail (default install directory, PROJ_LIB /// environment variable, installed callback, current directory). Therefore, /// do not expect the search path to override the other methods of specifying /// the location of resource files. /// </summary> /// <param name="path">An array of strings specifying directories to look for /// files in.</param> public static void SetSearchPath(string[] path) { if (path != null && path.Length > 0) Proj.pj_set_searchpath(path.Length, path); } /// <summary> /// Transform coordinates from one projection system to another /// </summary> /// <param name="dst">The destination projection</param> /// <param name="x">The "X" coordinate values.</param> /// <param name="y">The "Y" coordinate values.</param> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized or the transformation failed. The message will indicate the error. /// </exception> /// <exception cref="System.ArgumentException"> /// May be thrown for any of the following reasons: /// <list type="bullet"> /// <item>The "x" array is null</item> /// <item>The "y" array is null</item> /// <item>The length of the x and y arrays don't match</item> /// </list> /// </exception> public void Transform (Projection dst, double[] x, double[] y) { this.Transform(dst, x, y, null); } /// <summary> /// Transform coordinates from one projection system to another /// </summary> /// <param name="dst">The destination projection</param> /// <param name="x">The "X" coordinate values.</param> /// <param name="y">The "Y" coordinate values.</param> /// <param name="z">The "Z" coordinate values.</param> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized or the transformation failed. The message will indicate the error. /// </exception> /// <exception cref="System.ArgumentException"> /// May be thrown for any of the following reasons: /// <list type="bullet"> /// <item>The "x" array is null</item> /// <item>The "y" array is null</item> /// <item>The length of the x, y and z (if not null) arrays don't match</item> /// </list> /// </exception> public void Transform (Projection dst, double[] x, double[] y, double[] z) { Projection.Transform(this, dst, x, y, z); } /// <summary> /// Transform coordinates from one projection system to another /// </summary> /// <param name="src">The source projection</param> /// <param name="dst">The destination projection</param> /// <param name="x">The "X" coordinate values.</param> /// <param name="y">The "Y" coordinate values.</param> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized or the transformation failed. The message will indicate the error. /// </exception> /// <exception cref="System.ArgumentException"> /// May be thrown for any of the following reasons: /// <list type="bullet"> /// <item>The "x" array is null</item> /// <item>The "y" array is null</item> /// <item>The length of the x and y arrays don't match</item> /// </list> /// </exception> public static void Transform (Projection src, Projection dst, double[] x, double[] y) { Projection.Transform(src, dst, x, y, null); } /// <summary> /// Transform coordinates from one projection system to another /// </summary> /// <param name="src">The source projection</param> /// <param name="dst">The destination projection</param> /// <param name="x">The "X" coordinate values.</param> /// <param name="y">The "Y" coordinate values.</param> /// <param name="z">The "Z" coordinate values.</param> /// <exception cref="System.ApplicationException">Thrown when the projection is /// not initialized or the transformation failed. The message will indicate the error. /// </exception> /// <exception cref="System.ArgumentException"> /// May be thrown for any of the following reasons: /// <list type="bullet"> /// <item>The "x" array is null</item> /// <item>The "y" array is null</item> /// <item>The length of the x, y and z (if not null) arrays don't match</item> /// </list> /// </exception> public static void Transform (Projection src, Projection dst, double[] x, double[] y, double[] z) { Projection.CheckInitialized(src); Projection.CheckInitialized(dst); if (x == null) { throw new ArgumentException("Argument is required", "x"); } if (y == null) { throw new ArgumentException("Argument is required", "y"); } if (x.Length != y.Length || (z != null && z.Length != x.Length)) { throw new ArgumentException("Coordinate arrays must have the same length"); } if (src.IsLatLong) { for (int i = 0; i < x.Length; i++) { x[i] *= Proj.DEG_TO_RAD; y[i] *= Proj.DEG_TO_RAD; } } int result = Proj.pj_transform(src.prj, dst.prj, x.Length, 1, x, y, z); if (result != 0) { string message = "Tranformation Error"; int errno = GetErrNo(); if (errno != 0) message = Projection.GetErrorMessage(errno); throw new ApplicationException(message); } if (dst.IsLatLong) { for (int i = 0; i < x.Length; i++) { x[i] *= Proj.RAD_TO_DEG; y[i] *= Proj.RAD_TO_DEG; } } } #region IDisposable Members public void Dispose() { if (this.prj != IntPtr.Zero) Proj.pj_free(this.prj); } #endregion } }
proj_api_test.cs
/*============================================================================ * AUTHOR: Eric G. Miller * DATE: 2004-09-15 * PURPOSE: Performs some tests of the ProjApi wrapper * COPYRIGHT: Copyright (c) 2004, 2010 California Department of Fish and Game * LICENSE: MIT Style * Permission is hereby granted, free of charge, to any person obtaining a * copy of this software and associated documentation files (the "Software"), * to deal in the Software without restriction, including without limitation * the rights to use, copy, modify, merge, publish, distribute, sublicense, * and/or sell copies of the Software, and to permit persons to whom the * Software is furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included * in all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER * DEALINGS IN THE SOFTWARE. * * CHANGES: * For Proj-4.7.0 (2010-01-29, Eric G. Miller) * - Modified for changes introduced in the pj_api.cs file. *===========================================================================*/ using System; using System.Runtime.InteropServices; using ProjApi; public class ProjApiTest { /// <summary> /// Some testing of the proj_api classes /// </summary> [STAThread] static void Main(string[] args) { IntPtr projPJ = Proj.pj_init_plus(String.Join(" ", args)); if (projPJ != IntPtr.Zero) { Console.WriteLine("Initialization succeeded!"); Console.WriteLine(Proj.pj_get_def(projPJ, 0)); Proj.pj_free(projPJ); } else { Console.WriteLine("Initialization failed!"); int errno = Projection.GetErrNo(); if (errno != 0) { string message = Projection.GetErrorMessage(errno); Console.WriteLine(message); } } // begin tests int ntests = 0; int nsuccess = 0; ntests++; Console.Write("Testing pj_set_searchpath ... "); string[] path = new string[] {System.Environment.CurrentDirectory}; Proj.pj_set_searchpath(path.Length, path); Console.WriteLine("succeeded"); nsuccess++; ntests++; Console.Write("Testing pj_init ..."); if (Test_pj_init()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_init_plus ..."); if (Test_pj_init_plus()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_fwd ..."); if (Test_pj_fwd()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_inv ..."); if (Test_pj_inv()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_transform ..."); if (Test_pj_transform()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_geocentric_to_geodetic ..."); if (Test_pj_geocentric_to_geodetic()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_geodetic_to_geocentric ..."); if (Test_pj_geodetic_to_geocentric()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_deallocate_grids ..."); if (Test_pj_deallocate_grids()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_is_latlong ..."); if (Test_pj_is_latlong()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_is_geocent ..."); if (Test_pj_is_geocent()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_pr_list ..."); if (Test_pj_pr_list()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_get_def ..."); if (Test_pj_get_def()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_latlong_from_proj ..."); if (Test_pj_latlong_from_proj()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_get_release ..."); if (Test_pj_get_release()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_datum_transform ..."); if (Test_pj_datum_transform()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_compare_datums ..."); if (Test_pj_compare_datums()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } ntests++; Console.Write("Testing pj_malloc (pj_dalloc) ..."); if (Test_pj_alloc()) { nsuccess++; Console.WriteLine("succeeded"); } else { Console.WriteLine("failed"); } Console.WriteLine("{0} Tests, {1} Successes, {2} Failures", ntests, nsuccess, ntests - nsuccess); // Test high level API Console.WriteLine("\nTesting Projection API"); Test_Projection_API(); Console.ReadLine(); } static void WriteProjError(string test) { Console.Error.WriteLine("Test {0} failed!", test); int errno = Projection.GetErrNo(); if (errno != 0) { string message = Projection.GetErrorMessage(errno); Console.Error.WriteLine(message); } } static bool Test_pj_init() { string[] args = {"+proj=lcc", "+lat_1=33", "+lat_2=45", "+datum=NAD27", "+nodefs"}; IntPtr projPJ = Proj.pj_init(args.Length, args); if (projPJ == IntPtr.Zero) { WriteProjError("pj_init"); return false; } else { Proj.pj_free(projPJ); return true; } } static bool Test_pj_init_plus() { string arg = "+proj=lcc +lat_1=33 +lat_2=45 +datum=NAD27 +nodefs"; IntPtr projPJ = Proj.pj_init_plus(arg); if (projPJ == IntPtr.Zero) { WriteProjError("pj_init_plus"); return false; } else { Proj.pj_free(projPJ); return true; } } static bool Test_pj_fwd() { IntPtr projPJ = Proj.pj_init_plus(@"+proj=aea +lat_0=0 +lon_0=-120 " + @"+lat_1=34 +lat_2=40.5 +y_0=-4000000 +datum=NAD83"); if (projPJ == IntPtr.Zero) { WriteProjError("pj_fwd (pj_init_plus)"); return false; } else { ProjUV uv; uv.u = -120.0 * Proj.DEG_TO_RAD; uv.v = 34.0 * Proj.DEG_TO_RAD; uv = Proj.pj_fwd(uv, projPJ); Proj.pj_free(projPJ); if (uv.u == System.Double.MaxValue || uv.v == System.Double.MaxValue) { WriteProjError("pj_fwd"); return false; } else { Console.Write(" ({0},{1}) ", uv.u, uv.v); return true; } } } static bool Test_pj_inv() { IntPtr projPJ = Proj.pj_init_plus(@"+proj=aea +lat_0=0 +lon_0=-120 " + @"+lat_1=34 +lat_2=40.5 +y_0=-4000000 +datum=NAD83"); if (projPJ == IntPtr.Zero) { WriteProjError("pj_inv (pj_init_plus)"); return false; } else { ProjUV uv; uv.u = 0.0; uv.v = -446166.97; uv = Proj.pj_inv(uv, projPJ); Proj.pj_free(projPJ); if (uv.u == System.Double.MaxValue || uv.v == System.Double.MaxValue) { WriteProjError("pj_inv"); return false; } else { Console.Write(" ({0},{1}) ", uv.u * Proj.RAD_TO_DEG , uv.v * Proj.RAD_TO_DEG); return true; } } } static bool Test_pj_transform() { double[] x = {-119, -120, -121}; double[] y = {38, 39, 40}; for (int i = 0; i < x.Length; i++) { x[i] *= Proj.DEG_TO_RAD; y[i] *= Proj.DEG_TO_RAD; } IntPtr src = Proj.pj_init_plus("+proj=latlong +datum=NAD27 +nadgrids=conus +nodefs"); IntPtr dst = Proj.pj_init_plus(@"+proj=aea +lat_0=0 +lon_0=-120 " + @"+lat_1=34 +lat_2=40.5 +y_0=-4000000 +datum=NAD83 +nodefs"); int errno = Proj.pj_transform(src, dst, x.Length, 1, x, y, null); Proj.pj_free(src); Proj.pj_free(dst); if (errno != 0) { WriteProjError("pj_transform"); return false; } else { return true; } } static bool Test_pj_geocentric_to_geodetic() { return false; } static bool Test_pj_geodetic_to_geocentric() { return false; } static bool Test_pj_deallocate_grids() { Proj.pj_deallocate_grids(); return true; } static bool Test_pj_is_latlong() { IntPtr projPJ = Proj.pj_init_plus("+proj=latlong +datum=NAD83 +nodefs"); if (0 == Proj.pj_is_latlong(projPJ)) { WriteProjError("pj_is_latlong"); Proj.pj_free(projPJ); return false; } else { Proj.pj_free(projPJ); return true; } } static bool Test_pj_is_geocent() { IntPtr projPJ = Proj.pj_init_plus("+proj=latlong +datum=NAD83 +nodefs"); if (0 != Proj.pj_is_geocent(projPJ)) { WriteProjError("pj_is_geocent"); Proj.pj_free(projPJ); return false; } else { Proj.pj_free(projPJ); return true; } } static bool Test_pj_pr_list() { IntPtr projPJ = Proj.pj_init_plus("+proj=latlong +datum=NAD83 +nodefs"); Proj.pj_pr_list(projPJ); Proj.pj_free(projPJ); return true; } static bool Test_pj_get_def() { bool testResult = false; string orig = @"+proj=aea +lat_0=0 +lon_0=-120 +lat_1=34 +lat_2=40.5 +y_0=-4000000 +datum=NAD83 +nodefs"; IntPtr projPJ = Proj.pj_init_plus(orig); IntPtr pDef = Proj.pj_get_def(projPJ, 0); string result = Marshal.PtrToStringAnsi(pDef); Proj.pj_dalloc(pDef); IntPtr pErrno = Proj.pj_get_errno_ref(); int errno = Marshal.ReadInt32(pErrno); if (errno != 0) { WriteProjError("pj_get_def"); } else { Console.Error.WriteLine("ORIGINAL: {0}\nRESULT: {1}", orig, result); testResult = true; } Proj.pj_free(projPJ); return testResult; } static bool Test_pj_latlong_from_proj() { string orig = @"+proj=aea +lat_0=0 +lon_0=-120 +lat_1=34 +lat_2=40.5 +y_0=-4000000 +datum=NAD83 +nodefs"; IntPtr projPJ = Proj.pj_init_plus(orig); IntPtr dstPJ = Proj.pj_latlong_from_proj(projPJ); IntPtr pDef = Proj.pj_get_def(dstPJ, 0); string result = Marshal.PtrToStringAnsi(pDef); Proj.pj_dalloc(pDef); Proj.pj_free(projPJ); Proj.pj_free(dstPJ); if (result == null) { WriteProjError("pj_latlong_from_proj"); return false; } else { Console.WriteLine(result); return true; } } static bool Test_pj_get_release() { bool result = true; try { // Don't free result IntPtr pRelease = Proj.pj_get_release(); string release = Marshal.PtrToStringAnsi(pRelease); Console.WriteLine(release); } catch { result = false; } return result; } static bool Test_pj_datum_transform() { bool result = true; try { IntPtr src = Proj.pj_init_plus("+proj=latlong +datum=NAD27 +nadgrids=conus +nodefs"); IntPtr dst = Proj.pj_init_plus("+proj=latlong +datum=NAD83 +nodefs"); double[] x = {-120.125 * Proj.DEG_TO_RAD}; double[] y = {38.5 * Proj.DEG_TO_RAD}; Console.WriteLine("\t({0}, {1})", x[0] * Proj.RAD_TO_DEG, y[0] * Proj.RAD_TO_DEG); int errno = Proj.pj_datum_transform(src, dst, 1, 1, x, y, null); if (errno != 0) { WriteProjError("pj_datum_transform"); result = false; } else { Console.WriteLine("\n\t({0}, {1})", x[0] * Proj.RAD_TO_DEG, y[0] * Proj.RAD_TO_DEG); } Proj.pj_free(src); Proj.pj_free(dst); } catch (Exception e) { Console.Error.WriteLine(e.Message); result = false; } return result; } static bool Test_pj_compare_datums() { bool result = true; try { IntPtr src = Proj.pj_init_plus("+proj=latlong +datum=NAD27 +nadgrids=conus +nodefs"); IntPtr dst = Proj.pj_init_plus("+proj=latlong +datum=NAD83 +nodefs"); int same = Proj.pj_compare_datums(src, dst); if (same != 0) { WriteProjError("pj_compare_datums"); result = false; } Proj.pj_free(src); Proj.pj_free(dst); } catch (Exception e) { Console.Error.WriteLine(e.Message); result = false; } return result; } static bool Test_pj_alloc() { bool result = true; try { IntPtr memory = Proj.pj_malloc(512); if (memory == null) { result = false; WriteProjError("pj_malloc"); } else { Proj.pj_dalloc(memory); } } catch (Exception e) { Console.Error.WriteLine(e.Message); result = false; } return result; } static void Test_Projection_API() { Projection.SetSearchPath(new string[] {System.Environment.CurrentDirectory}); using ( Projection src = new Projection(@"+proj=latlong +datum=NAD27 +nadgrids=conus +nodefs"), dst = new Projection(@"+proj=aea +lat_0=0 +lon_0=-120 +lat_1=34 +lat_2=40.5 +y_0=-4000000 +datum=NAD83 +nodefs")) { Console.WriteLine("src.Definition = {0}", src.Definition); Console.WriteLine("dst.Definition = {0}", dst.Definition); Console.WriteLine("src (.ToString()) = {0}", src); Console.WriteLine("dst (.ToString()) = {0}", dst); Console.WriteLine("latlong.Definition = {0}", dst.GetLatLong().Definition); Console.WriteLine("src.IsLatLong = {0}", src.IsLatLong); Console.WriteLine("dst.IsLatLong = {0}", dst.IsLatLong); Console.WriteLine("src.IsGeoCentric = {0}", src.IsGeoCentric); Console.WriteLine("dst.IsGeoCentric = {0}", dst.IsGeoCentric); Console.WriteLine("src.GetType() = {0}", src.GetType()); double[] x = { -116, -117, -118, -119, -120, -121 }; double[] y = { 34, 35, 36, 37, 38, 39 }; double[] z = { 0, 10, 20, 30, 40, 50 }; Console.WriteLine("Original Coordinates:"); for (int i = 0; i < x.Length; i++) { Console.WriteLine("\t({0}, {1}, {2})", x[i], y[i], z[i]); } Console.WriteLine("Trying Projection.Transform(src, dst, x, y)"); try { Projection.Transform(src, dst, x, y); Console.WriteLine("Transformed Coordinates:"); for (int i = 0; i < x.Length; i++) { Console.WriteLine("\t({0}, {1}, {2})", x[i], y[i], z[i]); } } catch (Exception e) { Console.Error.WriteLine("Exception: {0}", e.Message); return; } Console.WriteLine("Trying Projection.Transform(dst, src, x, y, z)"); try { Projection.Transform(dst, src, x, y, z); Console.WriteLine("Original Coordinates ?"); for (int i = 0; i < x.Length; i++) { Console.WriteLine("\t({0}, {1}, {2})", x[i], y[i], z[i]); } } catch (Exception e) { Console.Error.WriteLine("Exception: {0}", e.Message); return; } Console.WriteLine("Trying src.Transform(dst, x, y, z)"); try { src.Transform(dst, x, y, z); Console.WriteLine("Transformed Coordinates:"); for (int i = 0; i < x.Length; i++) { Console.WriteLine("\t({0}, {1}, {2})", x[i], y[i], z[i]); } } catch (Exception e) { Console.Error.WriteLine("Exception: {0}", e.Message); return; } Console.WriteLine("Trying dst.Transform(src, x, y)"); try { dst.Transform(src, x, y); Console.WriteLine("Original Coordinates ?"); for (int i = 0; i < x.Length; i++) { Console.WriteLine("\t({0}, {1}, {2})", x[i], y[i], z[i]); } } catch (Exception e) { Console.Error.WriteLine("Exception: {0}", e.Message); return; } } } }