/**
 * Interfaces to an external shared library to which we pipe coordinate values
 * and then read back transformed values.  Most useful in combination with
 * PROJ coordinate transform program for reprojecting coordinates.
 *
 * Uses JNI interface to call native methods to define transformation and then
 * to transform points between coordinate systems.
 */

/*
 * $Id$
 */
package net.sourceforge.mapyrus;

import java.util.Enumeration;
import java.util.Hashtable;
import java.io.*;

public class WorldCoordinateTransform
{
	/*
	 * Native methods implementing defintion and transformation
	 * between coordinate systems and retrieving error message when something
	 * goes wrong.
	 */
	private static native int define(String description);
	private static native int transform(int t1, int t2, double []coords, int nCoords);

	static private Hashtable mDefinedCoordinateSystems;

	static
	{
		System.loadLibrary("mapyrusproj");
		mDefinedCoordinateSystems = new Hashtable();
	}

	/**
	 * Define a coordinate system.  Synchronized here because external
	 * library may not be thread-safe.
	 */
	static private synchronized int defineCoordinateSystem(String description)
		throws MapyrusException
	{
		Integer definition;
		int newProjection;
		
		definition = (Integer)mDefinedCoordinateSystems.get(description);
		if (definition == null)
		{
			newProjection = define(description);
			if (newProjection < 0)
			{
				throw new MapyrusException("Failed to define coordinate system " +
					description);
			}
			definition = new Integer(newProjection);
			mDefinedCoordinateSystems.put(description, definition);
		}
		return(definition.intValue());
	}

	/**
 	 * Convert X, Y coordinates from one coordinate system to another.
 	 * Synchronized here because external library may not be thread-safe.
 	 * @param p1 is source coordinate system.
 	 * @param p2 is destination coordinate system.
 	 * @param coords is array of X, Y coordinates to transform.
 	 */
	private static synchronized void transform(int p1, int p2,
		double []coords) throws MapyrusException
	{
		int nTransformed = transform(p1, p2, coords, coords.length / 2);

		if (nTransformed != coords.length)
		{
			Integer id;
			String sourceName = null, destName = null;

			/*
			 * Find the names of the two coordinate systems that were used.
			 */
			Enumeration e = mDefinedCoordinateSystems.keys();
			while (e.hasMoreElements())
			{
				String s = (String)e.nextElement();
				id = (Integer)mDefinedCoordinateSystems.get(s);
				if (id.intValue() == p1)
					sourceName = s;
				if (id.intValue() == p2)
					destName = s;
			}
			throw new MapyrusException("Failed to transform coordinates " +
				coords[nTransformed * 2] + " " + coords[nTransformed * 2 + 1] +
				" from '" + sourceName + "' to '" + destName + "'");
		}
	}

	/*
	 * Ids of the two coordinate systems in this transformation.
	 */	
	private int mSourceSystem;
	private int mDestinationSystem;

	/**
	 * Define a transformation between two coordinate systems.
	 */
	public WorldCoordinateTransform(String system1, String system2)
		throws MapyrusException
	{
		mSourceSystem = defineCoordinateSystem(system1);
		mDestinationSystem = defineCoordinateSystem(system2);
	}

	/**
	 * Transform coordinates from first coordinate system to the second.
	 * @param coords is array of X, Y coordinate values to be transformed.
	 */
	public void forwardTransform(double []coords) throws MapyrusException
	{
		transform(mSourceSystem, mDestinationSystem, coords);
	}

	/**
	 * Transform coordinates in reverse, from second coordinate system to the first.
	 * @param coords is array of X, Y coordinate values to be transformed.
	 */
	public void backwardTransform(double []coords) throws MapyrusException
	{
		transform(mSourceSystem, mDestinationSystem, coords);
	}
}

@@ -1477,16 +1477,17 @@
  system 
+'
 %22 +%0A%09%09%09%09
@@ -1494,24 +1494,30 @@
 %09description
+ + %22'%22
 );%0A%09%09%09%7D%0A%09%09%09d
@@ -2156,16 +2156,20 @@
 sformed 
+* 2 
 != coord
@@ -3435,32 +3435,76 @@
 rusException%0A%09%7B%0A
+%09%09if (mSourceSystem != mDestinationSystem)%0A%09
 %09%09transform(mSou
@@ -3788,25 +3788,19 @@
 on%0A%09%7B%0A%09%09
-transform
+if 
 (mSource
@@ -3797,33 +3797,35 @@
 f (mSourceSystem
-,
+ !=
  mDestinationSys
@@ -3819,32 +3819,80 @@
 estinationSystem
+)%0A%09%09%09transform(mDestinationSystem, mSourceSystem
 , coords);%0A%09%7D%0A%7D%0A

Fix backwards transformation. Skip null transformations. Check for transformation error correctly.