Index: applications/editors/josm/plugins/rgisopen/LICENSE
===================================================================
--- applications/editors/josm/plugins/rgisopen/LICENSE	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/LICENSE	(revision 23351)
@@ -0,0 +1,339 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 2, June 1991
+
+ Copyright (C) 1989, 1991 Free Software Foundation, Inc.,
+ 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The licenses for most software are designed to take away your
+freedom to share and change it.  By contrast, the GNU General Public
+License is intended to guarantee your freedom to share and change free
+software--to make sure the software is free for all its users.  This
+General Public License applies to most of the Free Software
+Foundation's software and to any other program whose authors commit to
+using it.  (Some other Free Software Foundation software is covered by
+the GNU Lesser General Public License instead.)  You can apply it to
+your programs, too.
+
+  When we speak of free software, we are referring to freedom, not
+price.  Our General Public Licenses are designed to make sure that you
+have the freedom to distribute copies of free software (and charge for
+this service if you wish), that you receive source code or can get it
+if you want it, that you can change the software or use pieces of it
+in new free programs; and that you know you can do these things.
+
+  To protect your rights, we need to make restrictions that forbid
+anyone to deny you these rights or to ask you to surrender the rights.
+These restrictions translate to certain responsibilities for you if you
+distribute copies of the software, or if you modify it.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must give the recipients all the rights that
+you have.  You must make sure that they, too, receive or can get the
+source code.  And you must show them these terms so they know their
+rights.
+
+  We protect your rights with two steps: (1) copyright the software, and
+(2) offer you this license which gives you legal permission to copy,
+distribute and/or modify the software.
+
+  Also, for each author's protection and ours, we want to make certain
+that everyone understands that there is no warranty for this free
+software.  If the software is modified by someone else and passed on, we
+want its recipients to know that what they have is not the original, so
+that any problems introduced by others will not reflect on the original
+authors' reputations.
+
+  Finally, any free program is threatened constantly by software
+patents.  We wish to avoid the danger that redistributors of a free
+program will individually obtain patent licenses, in effect making the
+program proprietary.  To prevent this, we have made it clear that any
+patent must be licensed for everyone's free use or not licensed at all.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                    GNU GENERAL PUBLIC LICENSE
+   TERMS AND CONDITIONS FOR COPYING, DISTRIBUTION AND MODIFICATION
+
+  0. This License applies to any program or other work which contains
+a notice placed by the copyright holder saying it may be distributed
+under the terms of this General Public License.  The "Program", below,
+refers to any such program or work, and a "work based on the Program"
+means either the Program or any derivative work under copyright law:
+that is to say, a work containing the Program or a portion of it,
+either verbatim or with modifications and/or translated into another
+language.  (Hereinafter, translation is included without limitation in
+the term "modification".)  Each licensee is addressed as "you".
+
+Activities other than copying, distribution and modification are not
+covered by this License; they are outside its scope.  The act of
+running the Program is not restricted, and the output from the Program
+is covered only if its contents constitute a work based on the
+Program (independent of having been made by running the Program).
+Whether that is true depends on what the Program does.
+
+  1. You may copy and distribute verbatim copies of the Program's
+source code as you receive it, in any medium, provided that you
+conspicuously and appropriately publish on each copy an appropriate
+copyright notice and disclaimer of warranty; keep intact all the
+notices that refer to this License and to the absence of any warranty;
+and give any other recipients of the Program a copy of this License
+along with the Program.
+
+You may charge a fee for the physical act of transferring a copy, and
+you may at your option offer warranty protection in exchange for a fee.
+
+  2. You may modify your copy or copies of the Program or any portion
+of it, thus forming a work based on the Program, and copy and
+distribute such modifications or work under the terms of Section 1
+above, provided that you also meet all of these conditions:
+
+    a) You must cause the modified files to carry prominent notices
+    stating that you changed the files and the date of any change.
+
+    b) You must cause any work that you distribute or publish, that in
+    whole or in part contains or is derived from the Program or any
+    part thereof, to be licensed as a whole at no charge to all third
+    parties under the terms of this License.
+
+    c) If the modified program normally reads commands interactively
+    when run, you must cause it, when started running for such
+    interactive use in the most ordinary way, to print or display an
+    announcement including an appropriate copyright notice and a
+    notice that there is no warranty (or else, saying that you provide
+    a warranty) and that users may redistribute the program under
+    these conditions, and telling the user how to view a copy of this
+    License.  (Exception: if the Program itself is interactive but
+    does not normally print such an announcement, your work based on
+    the Program is not required to print an announcement.)
+
+These requirements apply to the modified work as a whole.  If
+identifiable sections of that work are not derived from the Program,
+and can be reasonably considered independent and separate works in
+themselves, then this License, and its terms, do not apply to those
+sections when you distribute them as separate works.  But when you
+distribute the same sections as part of a whole which is a work based
+on the Program, the distribution of the whole must be on the terms of
+this License, whose permissions for other licensees extend to the
+entire whole, and thus to each and every part regardless of who wrote it.
+
+Thus, it is not the intent of this section to claim rights or contest
+your rights to work written entirely by you; rather, the intent is to
+exercise the right to control the distribution of derivative or
+collective works based on the Program.
+
+In addition, mere aggregation of another work not based on the Program
+with the Program (or with a work based on the Program) on a volume of
+a storage or distribution medium does not bring the other work under
+the scope of this License.
+
+  3. You may copy and distribute the Program (or a work based on it,
+under Section 2) in object code or executable form under the terms of
+Sections 1 and 2 above provided that you also do one of the following:
+
+    a) Accompany it with the complete corresponding machine-readable
+    source code, which must be distributed under the terms of Sections
+    1 and 2 above on a medium customarily used for software interchange; or,
+
+    b) Accompany it with a written offer, valid for at least three
+    years, to give any third party, for a charge no more than your
+    cost of physically performing source distribution, a complete
+    machine-readable copy of the corresponding source code, to be
+    distributed under the terms of Sections 1 and 2 above on a medium
+    customarily used for software interchange; or,
+
+    c) Accompany it with the information you received as to the offer
+    to distribute corresponding source code.  (This alternative is
+    allowed only for noncommercial distribution and only if you
+    received the program in object code or executable form with such
+    an offer, in accord with Subsection b above.)
+
+The source code for a work means the preferred form of the work for
+making modifications to it.  For an executable work, complete source
+code means all the source code for all modules it contains, plus any
+associated interface definition files, plus the scripts used to
+control compilation and installation of the executable.  However, as a
+special exception, the source code distributed need not include
+anything that is normally distributed (in either source or binary
+form) with the major components (compiler, kernel, and so on) of the
+operating system on which the executable runs, unless that component
+itself accompanies the executable.
+
+If distribution of executable or object code is made by offering
+access to copy from a designated place, then offering equivalent
+access to copy the source code from the same place counts as
+distribution of the source code, even though third parties are not
+compelled to copy the source along with the object code.
+
+  4. You may not copy, modify, sublicense, or distribute the Program
+except as expressly provided under this License.  Any attempt
+otherwise to copy, modify, sublicense or distribute the Program is
+void, and will automatically terminate your rights under this License.
+However, parties who have received copies, or rights, from you under
+this License will not have their licenses terminated so long as such
+parties remain in full compliance.
+
+  5. You are not required to accept this License, since you have not
+signed it.  However, nothing else grants you permission to modify or
+distribute the Program or its derivative works.  These actions are
+prohibited by law if you do not accept this License.  Therefore, by
+modifying or distributing the Program (or any work based on the
+Program), you indicate your acceptance of this License to do so, and
+all its terms and conditions for copying, distributing or modifying
+the Program or works based on it.
+
+  6. Each time you redistribute the Program (or any work based on the
+Program), the recipient automatically receives a license from the
+original licensor to copy, distribute or modify the Program subject to
+these terms and conditions.  You may not impose any further
+restrictions on the recipients' exercise of the rights granted herein.
+You are not responsible for enforcing compliance by third parties to
+this License.
+
+  7. If, as a consequence of a court judgment or allegation of patent
+infringement or for any other reason (not limited to patent issues),
+conditions are imposed on you (whether by court order, agreement or
+otherwise) that contradict the conditions of this License, they do not
+excuse you from the conditions of this License.  If you cannot
+distribute so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you
+may not distribute the Program at all.  For example, if a patent
+license would not permit royalty-free redistribution of the Program by
+all those who receive copies directly or indirectly through you, then
+the only way you could satisfy both it and this License would be to
+refrain entirely from distribution of the Program.
+
+If any portion of this section is held invalid or unenforceable under
+any particular circumstance, the balance of the section is intended to
+apply and the section as a whole is intended to apply in other
+circumstances.
+
+It is not the purpose of this section to induce you to infringe any
+patents or other property right claims or to contest validity of any
+such claims; this section has the sole purpose of protecting the
+integrity of the free software distribution system, which is
+implemented by public license practices.  Many people have made
+generous contributions to the wide range of software distributed
+through that system in reliance on consistent application of that
+system; it is up to the author/donor to decide if he or she is willing
+to distribute software through any other system and a licensee cannot
+impose that choice.
+
+This section is intended to make thoroughly clear what is believed to
+be a consequence of the rest of this License.
+
+  8. If the distribution and/or use of the Program is restricted in
+certain countries either by patents or by copyrighted interfaces, the
+original copyright holder who places the Program under this License
+may add an explicit geographical distribution limitation excluding
+those countries, so that distribution is permitted only in or among
+countries not thus excluded.  In such case, this License incorporates
+the limitation as if written in the body of this License.
+
+  9. The Free Software Foundation may publish revised and/or new versions
+of the General Public License from time to time.  Such new versions will
+be similar in spirit to the present version, but may differ in detail to
+address new problems or concerns.
+
+Each version is given a distinguishing version number.  If the Program
+specifies a version number of this License which applies to it and "any
+later version", you have the option of following the terms and conditions
+either of that version or of any later version published by the Free
+Software Foundation.  If the Program does not specify a version number of
+this License, you may choose any version ever published by the Free Software
+Foundation.
+
+  10. If you wish to incorporate parts of the Program into other free
+programs whose distribution conditions are different, write to the author
+to ask for permission.  For software which is copyrighted by the Free
+Software Foundation, write to the Free Software Foundation; we sometimes
+make exceptions for this.  Our decision will be guided by the two goals
+of preserving the free status of all derivatives of our free software and
+of promoting the sharing and reuse of software generally.
+
+                            NO WARRANTY
+
+  11. BECAUSE THE PROGRAM IS LICENSED FREE OF CHARGE, THERE IS NO WARRANTY
+FOR THE PROGRAM, TO THE EXTENT PERMITTED BY APPLICABLE LAW.  EXCEPT WHEN
+OTHERWISE STATED IN WRITING THE COPYRIGHT HOLDERS AND/OR OTHER PARTIES
+PROVIDE THE PROGRAM "AS IS" WITHOUT WARRANTY OF ANY KIND, EITHER EXPRESSED
+OR IMPLIED, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
+MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE.  THE ENTIRE RISK AS
+TO THE QUALITY AND PERFORMANCE OF THE PROGRAM IS WITH YOU.  SHOULD THE
+PROGRAM PROVE DEFECTIVE, YOU ASSUME THE COST OF ALL NECESSARY SERVICING,
+REPAIR OR CORRECTION.
+
+  12. IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MAY MODIFY AND/OR
+REDISTRIBUTE THE PROGRAM AS PERMITTED ABOVE, BE LIABLE TO YOU FOR DAMAGES,
+INCLUDING ANY GENERAL, SPECIAL, INCIDENTAL OR CONSEQUENTIAL DAMAGES ARISING
+OUT OF THE USE OR INABILITY TO USE THE PROGRAM (INCLUDING BUT NOT LIMITED
+TO LOSS OF DATA OR DATA BEING RENDERED INACCURATE OR LOSSES SUSTAINED BY
+YOU OR THIRD PARTIES OR A FAILURE OF THE PROGRAM TO OPERATE WITH ANY OTHER
+PROGRAMS), EVEN IF SUCH HOLDER OR OTHER PARTY HAS BEEN ADVISED OF THE
+POSSIBILITY OF SUCH DAMAGES.
+
+                     END OF TERMS AND CONDITIONS
+
+            How to Apply These Terms to Your New Programs
+
+  If you develop a new program, and you want it to be of the greatest
+possible use to the public, the best way to achieve this is to make it
+free software which everyone can redistribute and change under these terms.
+
+  To do so, attach the following notices to the program.  It is safest
+to attach them to the start of each source file to most effectively
+convey the exclusion of warranty; and each file should have at least
+the "copyright" line and a pointer to where the full notice is found.
+
+    <one line to give the program's name and a brief idea of what it does.>
+    Copyright (C) <year>  <name of author>
+
+    This program is free software; you can redistribute it and/or modify
+    it under the terms of the GNU General Public License as published by
+    the Free Software Foundation; either version 2 of the License, or
+    (at your option) any later version.
+
+    This program is distributed in the hope that it will be useful,
+    but WITHOUT ANY WARRANTY; without even the implied warranty of
+    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
+    GNU General Public License for more details.
+
+    You should have received a copy of the GNU General Public License along
+    with this program; if not, write to the Free Software Foundation, Inc.,
+    51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
+
+Also add information on how to contact you by electronic and paper mail.
+
+If the program is interactive, make it output a short notice like this
+when it starts in an interactive mode:
+
+    Gnomovision version 69, Copyright (C) year name of author
+    Gnomovision comes with ABSOLUTELY NO WARRANTY; for details type `show w'.
+    This is free software, and you are welcome to redistribute it
+    under certain conditions; type `show c' for details.
+
+The hypothetical commands `show w' and `show c' should show the appropriate
+parts of the General Public License.  Of course, the commands you use may
+be called something other than `show w' and `show c'; they could even be
+mouse-clicks or menu items--whatever suits your program.
+
+You should also get your employer (if you work as a programmer) or your
+school, if any, to sign a "copyright disclaimer" for the program, if
+necessary.  Here is a sample; alter the names:
+
+  Yoyodyne, Inc., hereby disclaims all copyright interest in the program
+  `Gnomovision' (which makes passes at compilers) written by James Hacker.
+
+  <signature of Ty Coon>, 1 April 1989
+  Ty Coon, President of Vice
+
+This General Public License does not permit incorporating your program into
+proprietary programs.  If your program is a subroutine library, you may
+consider it more useful to permit linking proprietary applications with the
+library.  If this is what you want to do, use the GNU Lesser General
+Public License instead of this License.
Index: applications/editors/josm/plugins/rgisopen/README
===================================================================
--- applications/editors/josm/plugins/rgisopen/README	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/README	(revision 23351)
@@ -0,0 +1,4 @@
+README 
+======
+
+Use http://rgis.spb.ru/map/ image file as overlay.
Index: applications/editors/josm/plugins/rgisopen/REVISION
===================================================================
--- applications/editors/josm/plugins/rgisopen/REVISION	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/REVISION	(revision 23351)
@@ -0,0 +1,3 @@
+svn: '.' is not a working copy
+<?xml version="1.0"?>
+<info>
Index: applications/editors/josm/plugins/rgisopen/build.xml
===================================================================
--- applications/editors/josm/plugins/rgisopen/build.xml	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/build.xml	(revision 23351)
@@ -0,0 +1,258 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<!--
+** This is a template build file for a JOSM  plugin.
+**
+** Maintaining versions
+** ====================
+** see README.template
+**
+** Usage
+** =====
+** To build it run
+**
+**    > ant  dist
+**
+** To install the generated plugin locally (in you default plugin directory) run
+**
+**    > ant  install
+**
+** The generated plugin jar is not automatically available in JOSMs plugin configuration
+** dialog. You have to check it in first.
+**
+** Use the ant target 'publish' to check in the plugin and make it available to other
+** JOSM users:
+**    set the properties commit.message and plugin.main.version
+** and run
+**    > ant  publish
+**
+**
+-->
+<project name="rgisopen" default="dist" basedir=".">
+
+    <!-- enter the SVN commit message -->
+    <property name="commit.message" value="New plugin, rgisopen" />
+    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
+    <property name="plugin.main.version" value="3400" />
+
+
+    <!--
+      ************************************************
+      ** should not be necessary to change the following properties
+     -->
+    <property name="josm"                   location="../../josm-latest.jar"/>
+    <property name="plugin.build.dir"       value="build"/>
+    <property name="plugin.src.dir"         value="src"/>
+    <!-- this is the directory where the plugin jar is copied to -->
+    <property name="plugin.dist.dir"        value="../../dist"/>
+    <property name="ant.build.javac.target" value="1.5"/>
+    <property name="plugin.dist.dir"        value="../../dist"/>
+    <property name="plugin.jar"             value="${plugin.dist.dir}/${ant.project.name}.jar"/>
+
+    <!--
+    **********************************************************
+    ** init - initializes the build
+    **********************************************************
+    -->
+    <target name="init">
+        <mkdir dir="${plugin.build.dir}"/>
+    </target>
+
+    <!--
+    **********************************************************
+    ** compile - complies the source tree
+    **********************************************************
+    -->
+    <target name="compile" depends="init">
+        <echo message="compiling sources for  ${plugin.jar} ... "/>
+        <javac srcdir="src" classpath="${josm};../../dist/piclayer.jar" debug="true" destdir="${plugin.build.dir}">
+            <compilerarg value="-Xlint:deprecation"/>
+            <compilerarg value="-Xlint:unchecked"/>
+        </javac>
+    </target>
+
+    <!--
+    **********************************************************
+    ** dist - creates the plugin jar
+    **********************************************************
+    -->
+    <target name="dist" depends="compile,revision">
+        <echo message="creating ${ant.project.name}.jar ... "/>
+        <copy todir="${plugin.build.dir}/resources">
+            <fileset dir="resources"/>
+        </copy>
+        <copy todir="${plugin.build.dir}/images">
+            <fileset dir="images"/>
+        </copy>
+        <copy todir="${plugin.build.dir}">
+            <fileset dir=".">
+                <include name="README" />
+                <include name="LICENSE" />
+            </fileset>
+        </copy>
+        <jar destfile="${plugin.jar}" basedir="${plugin.build.dir}">
+            <!--
+        ************************************************
+        ** configure these properties. Most of them will be copied to the plugins
+        ** manifest file. Property values will also show up in the list available
+        ** plugins: http://josm.openstreetmap.de/wiki/Plugins.
+        **
+        ************************************************
+    -->
+            <manifest>
+                <attribute name="Author" value="Ilya Zverev"/>
+                <attribute name="Plugin-Class" value="rgisopen.RGISOpenPlugin"/>
+                <attribute name="Plugin-Date" value="${version.entry.commit.date}"/>
+                <attribute name="Plugin-Description" value="Use rgis.spb.ru image as overlay"/>
+                <attribute name="Plugin-Icon" value="images/rgisicon.png"/>
+                <attribute name="Plugin-Link" value="http://rgis.spb.ru/map/"/>
+                <attribute name="Plugin-Mainversion" value="${plugin.main.version}"/>
+                <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/>
+		<attribute name="Plugin-Requires" value="PicLayer"/>
+            </manifest>
+        </jar>
+    </target>
+
+    <!--
+    **********************************************************
+    ** revision - extracts the current revision number for the
+    **    file build.number and stores it in the XML property
+    **    version.*
+    **********************************************************
+    -->
+    <target name="revision">
+
+        <exec append="false" output="REVISION" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="info"/>
+            <arg value="--xml"/>
+            <arg value="."/>
+        </exec>
+        <xmlproperty file="REVISION" prefix="version" keepRoot="false" collapseAttributes="true"/>
+        <delete file="REVISION"/>
+    </target>
+
+    <!--
+    **********************************************************
+    ** clean - clean up the build environment
+    **********************************************************
+    -->
+    <target name="clean">
+        <delete dir="${plugin.build.dir}"/>
+        <delete file="${plugin.jar}"/>
+    </target>
+
+    <!--
+    **********************************************************
+    ** install - install the plugin in your local JOSM installation
+    **********************************************************
+    -->
+    <target name="install" depends="dist">
+        <property environment="env"/>
+        <condition property="josm.plugins.dir" value="${env.APPDATA}/JOSM/plugins" else="${user.home}/.josm/plugins">
+            <and>
+                <os family="windows"/>
+            </and>
+        </condition>
+        <copy file="${plugin.jar}" todir="${josm.plugins.dir}"/>
+    </target>
+
+
+    <!--
+    ************************** Publishing the plugin *********************************** 
+    -->
+    <!--
+        ** extracts the JOSM release for the JOSM version in ../core and saves it in the 
+        ** property ${coreversion.info.entry.revision}
+        **
+        -->
+    <target name="core-info">
+        <exec append="false" output="core.info.xml" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="info"/>
+            <arg value="--xml"/>
+            <arg value="../../core"/>
+        </exec>
+        <xmlproperty file="core.info.xml" prefix="coreversion" keepRoot="true" collapseAttributes="true"/>
+        <echo>Building against core revision ${coreversion.info.entry.revision}.</echo>
+        <echo>Plugin-Mainversion is set to ${plugin.main.version}.</echo>
+        <delete file="core.info.xml" />
+    </target>
+
+    <!--
+        ** commits the source tree for this plugin
+        -->
+    <target name="commit-current">
+        <echo>Commiting the plugin source with message '${commit.message}' ...</echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="commit"/>
+            <arg value="-m '${commit.message}'"/>
+            <arg value="."/>
+        </exec>
+    </target>
+
+    <!--
+        ** updates (svn up) the source tree for this plugin
+        -->
+    <target name="update-current">
+        <echo>Updating plugin source ...</echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="up"/>
+            <arg value="."/>
+        </exec>
+        <echo>Updating ${plugin.jar} ...</echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="up"/>
+            <arg value="../dist/${plugin.jar}"/>
+        </exec>
+    </target>
+
+    <!--
+        ** commits the plugin.jar 
+        -->
+    <target name="commit-dist">
+        <echo>
+    ***** Properties of published ${plugin.jar} *****
+    Commit message    : '${commit.message}'                    
+    Plugin-Mainversion: ${plugin.main.version}
+    JOSM build version: ${coreversion.info.entry.revision}
+    Plugin-Version    : ${version.entry.commit.revision}
+    ***** / Properties of published ${plugin.jar} *****                    
+                        
+    Now commiting ${plugin.jar} ...
+    </echo>
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false">
+            <env key="LANG" value="C"/>
+            <arg value="-m '${commit.message}'"/>
+            <arg value="commit"/>
+            <arg value="${plugin.jar}"/>
+        </exec>
+    </target>
+
+    <!-- ** make sure svn is present as a command line tool ** -->
+    <target name="ensure-svn-present">
+        <exec append="true" output="svn.log" executable="svn" failifexecutionfails="false" failonerror="false" resultproperty="svn.exit.code">
+            <env key="LANG" value="C" />
+            <arg value="--version" />
+        </exec>
+        <fail message="Fatal: command 'svn --version' failed. Please make sure svn is installed on your system.">
+            <!-- return code not set at all? Most likely svn isn't installed -->
+            <condition>
+                <not>
+                    <isset property="svn.exit.code" />
+                </not>
+            </condition>
+        </fail>
+        <fail message="Fatal: command 'svn --version' failed. Please make sure a working copy of svn is installed on your system.">
+            <!-- error code from SVN? Most likely svn is not what we are looking on this system -->
+            <condition>
+                <isfailure code="${svn.exit.code}" />
+            </condition>
+        </fail>
+    </target>
+
+    <target name="publish" depends="ensure-svn-present,core-info,commit-current,update-current,clean,dist,commit-dist">
+    </target>
+</project>
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/AngleFormat.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/AngleFormat.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/AngleFormat.java	(revision 23351)
@@ -0,0 +1,184 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map;
+
+import java.text.*;
+
+/**
+ * A NumberFormat for formatting Angles in various commonly-found mapping styles.
+ */
+public class AngleFormat extends NumberFormat {
+
+	public final static String ddmmssPattern = "DdM";
+	public final static String ddmmssPattern2 = "DdM'S\"";
+	public final static String ddmmssLongPattern = "DdM'S\"W";
+	public final static String ddmmssLatPattern = "DdM'S\"N";
+	public final static String ddmmssPattern4 = "DdMmSs";
+	public final static String decimalPattern = "D.F";
+
+	private DecimalFormat format;
+	private String pattern;
+	private boolean isDegrees;
+
+	public AngleFormat() {
+		this(ddmmssPattern);
+	}
+	
+	public AngleFormat(String pattern) {
+		this(pattern, false);
+	}
+	
+	public AngleFormat(String pattern, boolean isDegrees) {
+		this.pattern = pattern;
+		this.isDegrees = isDegrees;
+		format = new DecimalFormat();
+		format.setMaximumFractionDigits(0);
+		format.setGroupingUsed(false);
+	}
+	
+	public StringBuffer format(long number, StringBuffer result, FieldPosition fieldPosition) {
+		return format((double)number, result, fieldPosition);
+	}
+
+	public StringBuffer format(double number, StringBuffer result, FieldPosition fieldPosition) {
+		int length = pattern.length();
+		int f;
+		boolean negative = false;
+
+		if (number < 0) {
+			for (int i = length-1; i >= 0; i--) {
+				char c = pattern.charAt(i);
+				if (c == 'W' || c == 'N') {
+					number = -number;
+					negative = true;
+					break;
+				}
+			}
+		}
+		
+		double ddmmss = isDegrees ? number : Math.toDegrees(number);
+		int iddmmss = (int)Math.round(ddmmss * 3600);
+		if (iddmmss < 0)
+			iddmmss = -iddmmss;
+		int fraction = iddmmss % 3600;
+
+		for (int i = 0; i < length; i++) {
+			char c = pattern.charAt(i);
+			switch (c) {
+			case 'R':
+				result.append(number);
+				break;
+			case 'D':
+				result.append((int)ddmmss);
+				break;
+			case 'M':
+				f = fraction / 60;
+				if (f < 10)
+					result.append('0');
+				result.append(f);
+				break;
+			case 'S':
+				f = fraction % 60;
+				if (f < 10)
+					result.append('0');
+				result.append(f);
+				break;
+			case 'F':
+				result.append(fraction);
+				break;
+			case 'W':
+				if (negative)
+					result.append('W');
+				else
+					result.append('E');
+				break;
+			case 'N':
+				if (negative)
+					result.append('S');
+				else
+					result.append('N');
+				break;
+			default:
+				result.append(c);
+				break;
+			}
+		}
+		return result;
+	}
+	
+	public Number parse(String text, ParsePosition parsePosition) {
+		double d = 0, m = 0, s = 0;
+		double result;
+		boolean negate = false;
+		int length = text.length();
+		if (length > 0) {
+			char c = Character.toUpperCase(text.charAt(length-1));
+			switch (c) {
+			case 'W':
+			case 'S':
+				negate = true;
+				// Fall into...
+			case 'E':
+			case 'N':
+				text = text.substring(0, length-1);
+				break;
+			}
+		}
+		int i = text.indexOf('d');
+		if (i == -1)
+			i = text.indexOf('\u00b0');
+		if (i != -1) {
+			String dd = text.substring(0, i);
+			String mmss = text.substring(i+1);
+			d = Double.valueOf(dd).doubleValue();
+			i = mmss.indexOf('m');
+			if (i == -1)
+				i = mmss.indexOf('\'');
+			if (i != -1) {
+				if (i != 0) {
+					String mm = mmss.substring(0, i);
+					m = Double.valueOf(mm).doubleValue();
+				}
+				if (mmss.endsWith("s") || mmss.endsWith("\""))
+					mmss = mmss.substring(0, mmss.length()-1);
+				if (i != mmss.length()-1) {
+					String ss = mmss.substring(i+1);
+					s = Double.valueOf(ss).doubleValue();
+				}
+				if (m < 0 || m > 59)
+					throw new NumberFormatException("Minutes must be between 0 and 59");
+				if (s < 0 || s >= 60)
+					throw new NumberFormatException("Seconds must be between 0 and 59");
+			} else if (i != 0)
+				m = Double.valueOf(mmss).doubleValue();
+			if (isDegrees)
+				result = MapMath.dmsToDeg(d, m, s);
+			else
+				result = MapMath.dmsToRad(d, m, s);
+		} else {
+			result = Double.parseDouble(text);
+			if (!isDegrees)
+				result = Math.toRadians(result);
+		}
+		if (parsePosition != null)
+			parsePosition.setIndex(text.length());
+		if (negate)
+			result = -result;
+		return new Double(result);
+	}
+}
+
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Datum.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Datum.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Datum.java	(revision 23351)
@@ -0,0 +1,63 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map;
+
+/**
+ * A geodetic datum. This isn't used (yet).
+ */
+public class Datum {
+	// Just a placeholder for now
+
+	String name;
+	Ellipsoid ellipsoid;
+	double deltaX, deltaY, deltaZ;
+	
+    public static Datum[] datums = {
+	    new Datum("ADINDAN", Ellipsoid.CLARKE_1880, -162, -12, -206),
+	    new Datum("ARC1950", Ellipsoid.CLARKE_1880, -143, -90, -294),
+	    new Datum("ARC1960", Ellipsoid.CLARKE_1880, -160,  -8, -300),
+	    new Datum("Australian Geodetic 1966", Ellipsoid.AUSTRALIAN, -133, -48, 148),
+	    new Datum("Australian Geodetic 984", Ellipsoid.AUSTRALIAN, -134, -48, 149),
+	    new Datum("CAMP_AREA_ASTRO", Ellipsoid.INTERNATIONAL_1967, -104, -129, 239),
+	    new Datum("Cape", Ellipsoid.CLARKE_1880, -136, -108, -292),
+	    new Datum("European Datum 1950", Ellipsoid.INTERNATIONAL_1967, -87, -98, -121),
+	    new Datum("European Datum 1979", Ellipsoid.INTERNATIONAL_1967, -86, -98, -119),
+	    new Datum("Geodetic Datum 1949", Ellipsoid.INTERNATIONAL_1967, 84, -22, 209),
+	    new Datum("Hong Kong 1963", Ellipsoid.INTERNATIONAL_1967, -156, -271, -189),
+	    new Datum("Hu Tzu Shan", Ellipsoid.INTERNATIONAL_1967, -634, -549, -201),
+//	    new Datum("Indian", Ellipsoid.EVEREST, 289, 734, 257),
+	    new Datum("NAD27", Ellipsoid.CLARKE_1866, -8, 160, 176),
+	    new Datum("NAD83", Ellipsoid.GRS_1980, 0, 0, 0),
+	    new Datum("Old Hawaiian mean", Ellipsoid.CLARKE_1866, 89, -279, -183),
+	    new Datum("OMAN", Ellipsoid.CLARKE_1880, -346, -1, 224),
+	    new Datum("Ordnance Survey 1936", Ellipsoid.AIRY, 375, -111, 431),
+	    new Datum("Puerto Rico", Ellipsoid.CLARKE_1866, 11, 72, -101),
+	    new Datum("Pulkovo 1942", Ellipsoid.KRASOVSKY, 27, -135, -89),
+	    new Datum("PROVISIONAL_S_AMERICAN_1956", Ellipsoid.INTERNATIONAL_1967, -288, 175, -376),
+	    new Datum("Tokyo", Ellipsoid.BESSEL, -128, 481, 664),
+	    new Datum("WGS72", Ellipsoid.WGS_1972, 0, 0, -4.5),
+	    new Datum("WGS84", Ellipsoid.WGS_1984, 0, 0, 0)
+	};
+
+	public Datum(String name, Ellipsoid ellipsoid, double deltaX, double deltaY, double deltaZ) {
+		this.name = name;
+		this.ellipsoid = ellipsoid;
+		this.deltaX = deltaX;
+		this.deltaY = deltaY;
+		this.deltaZ = deltaZ;
+	}
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/DegreeUnit.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/DegreeUnit.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/DegreeUnit.java	(revision 23351)
@@ -0,0 +1,56 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map;
+
+import java.text.*;
+
+public class DegreeUnit extends Unit {
+	
+	static final long serialVersionUID = -3212757578604686538L;
+	
+	private static AngleFormat format = new AngleFormat(AngleFormat.ddmmssPattern, true);
+	
+	public DegreeUnit() {
+		super("degree", "degrees", "deg", 1);
+	}
+	
+	public double parse(String s) throws NumberFormatException {
+		try {
+			return format.parse(s).doubleValue();
+		}
+		catch (java.text.ParseException e) {
+			throw new NumberFormatException(e.getMessage());
+		}
+	}
+	
+	public String format(double n) {
+		return format.format(n)+" "+abbreviation;
+	}
+	
+	public String format(double n, boolean abbrev) {
+		if (abbrev)
+			return format.format(n)+" "+abbreviation;
+		return format.format(n);
+	}
+	
+	public String format(double x, double y, boolean abbrev) {
+		if (abbrev)
+			return format.format(x)+"/"+format.format(y)+" "+abbreviation;
+		return format.format(x)+"/"+format.format(y);
+	}
+}
+
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Ellipsoid.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Ellipsoid.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Ellipsoid.java	(revision 23351)
@@ -0,0 +1,166 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+package com.jhlabs.map;
+
+import java.io.*;
+
+/**
+ * A class representing a geographic ellipsoid.
+ * Changes: Added Serializable interface by Bernhard Jenny, 18 May 2010
+ */
+public class Ellipsoid implements Cloneable, Serializable {
+
+    public String name;
+    public String shortName;
+    public double equatorRadius = 1.0;
+    public double poleRadius = 1.0;
+    public double eccentricity = 1.0;
+    public double eccentricity2 = 1.0;
+    // From: USGS PROJ package.
+    public final static Ellipsoid SPHERE = new Ellipsoid("sphere", 6371008.7714, 6371008.7714, 0.0, "Sphere");
+    public final static Ellipsoid BESSEL = new Ellipsoid("bessel", 6377397.155, 0.0, 299.1528128, "Bessel 1841");
+    public final static Ellipsoid CLARKE_1866 = new Ellipsoid("clrk66", 6378206.4, 6356583.8, 0.0, "Clarke 1866");
+    public final static Ellipsoid CLARKE_1880 = new Ellipsoid("clrk80", 6378249.145, 0.0, 293.4663, "Clarke 1880 mod.");
+    public final static Ellipsoid AIRY = new Ellipsoid("airy", 6377563.396, 6356256.910, 0.0, "Airy 1830");
+    public final static Ellipsoid WGS_1960 = new Ellipsoid("WGS60", 6378165.0, 0.0, 298.3, "WGS 60");
+    public final static Ellipsoid WGS_1966 = new Ellipsoid("WGS66", 6378145.0, 0.0, 298.25, "WGS 66");
+    public final static Ellipsoid WGS_1972 = new Ellipsoid("WGS72", 6378135.0, 0.0, 298.26, "WGS 72");
+    public final static Ellipsoid WGS_1984 = new Ellipsoid("WGS84", 6378137.0, 0.0, 298.257223563, "WGS 84");
+    public final static Ellipsoid KRASOVSKY = new Ellipsoid("krass", 6378245.0, 298.3, 0.0, "Krassovsky, 1942");
+    public final static Ellipsoid EVEREST = new Ellipsoid("evrst30", 6377276.345, 0.0, 300.8017, "Everest 1830");
+    public final static Ellipsoid INTERNATIONAL_1967 = new Ellipsoid("new_intl", 6378157.5, 6356772.2, 0.0, "New International 1967");
+    public final static Ellipsoid GRS_1980 = new Ellipsoid("GRS80", 6378137.0, 0.0, 298.257222101, "GRS 1980 (IUGG, 1980)");
+    public final static Ellipsoid AUSTRALIAN = new Ellipsoid("australian", 6378160.0, 6356774.7, 298.25, "Australian");
+    public final static Ellipsoid[] ellipsoids = {
+        SPHERE,
+        new Ellipsoid("MERIT", 6378137.0, 0.0, 298.257, "MERIT 1983"),
+        new Ellipsoid("SGS85", 6378136.0, 0.0, 298.257, "Soviet Geodetic System 85"),
+        GRS_1980,
+        new Ellipsoid("IAU76", 6378140.0, 0.0, 298.257, "IAU 1976"),
+        AIRY,
+        new Ellipsoid("APL4.9", 6378137.0, 0.0, 298.25, "Appl. Physics. 1965"),
+        new Ellipsoid("NWL9D", 6378145.0, 298.25, 0.0, "Naval Weapons Lab., 1965"),
+        new Ellipsoid("mod_airy", 6377340.189, 6356034.446, 0.0, "Modified Airy"),
+        new Ellipsoid("andrae", 6377104.43, 300.0, 0.0, "Andrae 1876 (Den., Iclnd.)"),
+        new Ellipsoid("aust_SA", 6378160.0, 0.0, 298.25, "Australian Natl & S. Amer. 1969"),
+        new Ellipsoid("GRS67", 6378160.0, 0.0, 298.2471674270, "GRS 67 (IUGG 1967)"),
+        BESSEL,
+        new Ellipsoid("bess_nam", 6377483.865, 0.0, 299.1528128, "Bessel 1841 (Namibia)"),
+        CLARKE_1866,
+        CLARKE_1880,
+        new Ellipsoid("CPM", 6375738.7, 0.0, 334.29, "Comm. des Poids et Mesures 1799"),
+        new Ellipsoid("delmbr", 6376428.0, 0.0, 311.5, "Delambre 1810 (Belgium)"),
+        new Ellipsoid("engelis", 6378136.05, 0.0, 298.2566, "Engelis 1985"),
+        EVEREST,
+        new Ellipsoid("evrst48", 6377304.063, 0.0, 300.8017, "Everest 1948"),
+        new Ellipsoid("evrst56", 6377301.243, 0.0, 300.8017, "Everest 1956"),
+        new Ellipsoid("evrst69", 6377295.664, 0.0, 300.8017, "Everest 1969"),
+        new Ellipsoid("evrstSS", 6377298.556, 0.0, 300.8017, "Everest (Sabah & Sarawak)"),
+        new Ellipsoid("fschr60", 6378166.0, 0.0, 298.3, "Fischer (Mercury Datum) 1960"),
+        new Ellipsoid("fschr60m", 6378155.0, 0.0, 298.3, "Modified Fischer 1960"),
+        new Ellipsoid("fschr68", 6378150.0, 0.0, 298.3, "Fischer 1968"),
+        new Ellipsoid("helmert", 6378200.0, 0.0, 298.3, "Helmert 1906"),
+        new Ellipsoid("hough", 6378270.0, 0.0, 297.0, "Hough"),
+        new Ellipsoid("intl", 6378388.0, 0.0, 297.0, "International 1909 (Hayford)"),
+        KRASOVSKY,
+        new Ellipsoid("kaula", 6378163.0, 0.0, 298.24, "Kaula 1961"),
+        new Ellipsoid("lerch", 6378139.0, 0.0, 298.257, "Lerch 1979"),
+        new Ellipsoid("mprts", 6397300.0, 0.0, 191.0, "Maupertius 1738"),
+        INTERNATIONAL_1967,
+        new Ellipsoid("plessis", 6376523.0, 6355863.0, 0.0, "Plessis 1817 France)"),
+        new Ellipsoid("SEasia", 6378155.0, 6356773.3205, 0.0, "Southeast Asia"),
+        new Ellipsoid("walbeck", 6376896.0, 6355834.8467, 0.0, "Walbeck"),
+        WGS_1960,
+        WGS_1966,
+        WGS_1972,
+        WGS_1984,
+        new Ellipsoid("NAD27", 6378249.145, 0.0, 293.4663, "NAD27: Clarke 1880 mod."),
+        new Ellipsoid("NAD83", 6378137.0, 0.0, 298.257222101, "NAD83: GRS 1980 (IUGG, 1980)"),};
+
+    public Ellipsoid() {
+    }
+
+    // One of of poleRadius or reciprocalFlattening must be specified, the other zero
+    public Ellipsoid(String shortName, double equatorRadius, double poleRadius, double reciprocalFlattening, String name) {
+        this.shortName = shortName;
+        this.name = name;
+        this.equatorRadius = equatorRadius;
+        this.poleRadius = poleRadius;
+        if (reciprocalFlattening != 0) {
+            double flattening = 1.0 / reciprocalFlattening;
+            double f = flattening;
+            eccentricity2 = 2 * f - f * f;
+            poleRadius = equatorRadius * Math.sqrt(1.0 - eccentricity2);
+        } else {
+            eccentricity2 = 1.0 - (poleRadius * poleRadius) / (equatorRadius * equatorRadius);
+        }
+        eccentricity = Math.sqrt(eccentricity2);
+    }
+
+    public Ellipsoid(String shortName, double equatorRadius, double eccentricity2, String name) {
+        this.shortName = shortName;
+        this.name = name;
+        this.equatorRadius = equatorRadius;
+        setEccentricitySquared(eccentricity2);
+    }
+
+    public Object clone() {
+        try {
+            Ellipsoid e = (Ellipsoid) super.clone();
+            return e;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        return name;
+    }
+
+    public void setShortName(String shortName) {
+        this.shortName = shortName;
+    }
+
+    public String getShortName() {
+        return shortName;
+    }
+
+    public void setEquatorRadius(double equatorRadius) {
+        this.equatorRadius = equatorRadius;
+    }
+
+    public double getEquatorRadius() {
+        return equatorRadius;
+    }
+
+    public void setEccentricitySquared(double eccentricity2) {
+        this.eccentricity2 = eccentricity2;
+        poleRadius = equatorRadius * Math.sqrt(1.0 - eccentricity2);
+        eccentricity = Math.sqrt(eccentricity2);
+    }
+
+    public double getEccentricitySquared() {
+        return eccentricity2;
+    }
+
+    public String toString() {
+        return name;
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/MapMath.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/MapMath.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/MapMath.java	(revision 23351)
@@ -0,0 +1,487 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+/**
+ * Changed normalizeLongitude to avoid instable computations with very small
+ * numbers: if the longitude angle is very close to the graticule boundary,
+ * return +/-PI.
+ * Bernhard Jenny, May 25 2010.
+ */
+package com.jhlabs.map;
+
+import java.awt.geom.*;
+import com.jhlabs.map.proj.*;
+
+public class MapMath {
+
+	public final static double HALFPI = Math.PI/2.0;
+	public final static double QUARTERPI = Math.PI/4.0;
+	public final static double TWOPI = Math.PI*2.0;
+	public final static double RTD = 180.0/Math.PI;
+	public final static double DTR = Math.PI/180.0;
+	public final static Rectangle2D WORLD_BOUNDS_RAD = new Rectangle2D.Double(-Math.PI, -Math.PI/2, Math.PI*2, Math.PI);
+	public final static Rectangle2D WORLD_BOUNDS = new Rectangle2D.Double(-180, -90, 360, 180);
+
+	/**
+	 * Degree versions of trigonometric functions
+	 */
+	public static double sind(double v) {
+		return Math.sin(v * DTR);
+	}
+	
+	public static double cosd(double v) {
+		return Math.cos(v * DTR);
+	}
+	
+	public static double tand(double v) {
+		return Math.tan(v * DTR);
+	}
+	
+	public static double asind(double v) {
+		return Math.asin(v) * RTD;
+	}
+	
+	public static double acosd(double v) {
+		return Math.acos(v) * RTD;
+	}
+	
+	public static double atand(double v) {
+		return Math.atan(v) * RTD;
+	}
+	
+	public static double atan2d(double y, double x) {
+		return Math.atan2(y, x) * RTD;
+	}
+	
+	public static double asin(double v) {
+		if (Math.abs(v) > 1.)
+			return v < 0.0 ? -Math.PI/2 : Math.PI/2;
+		return Math.asin(v);
+	}
+
+	public static double acos(double v) {
+		if (Math.abs(v) > 1.)
+			return v < 0.0 ? Math.PI : 0.0;
+		return Math.acos(v);
+	}
+
+	public static double sqrt(double v) {
+		return v < 0.0 ? 0.0 : Math.sqrt(v);
+	}
+	
+	public static double distance(double dx, double dy) {
+		return Math.sqrt(dx*dx+dy*dy);
+	}
+
+	public static double distance(Point2D.Double a, Point2D.Double b) {
+		return distance(a.x-b.x, a.y-b.y);
+	}
+
+	public static double hypot(double x, double y) {
+		if (x < 0.0)
+			x = -x;
+		else if (x == 0.0)
+			return y < 0.0 ? -y : y;
+		if (y < 0.0)
+			y = -y;
+		else if (y == 0.0)
+			return x;
+		if (x < y) {
+			x /= y;
+			return y * Math.sqrt(1.0 + x * x);
+		} else {
+			y /= x;
+			return x * Math.sqrt(1.0 + y * y);
+		}
+	}
+
+	public static double atan2(double y, double x) {
+		return Math.atan2(y, x);
+	}
+
+	public static double trunc(double v) {
+		return v < 0.0 ? Math.ceil(v) : Math.floor(v);
+	}
+	
+	public static double frac(double v) {
+		return v - trunc(v);
+	}
+	
+	public static double degToRad(double v) {
+		return v * Math.PI / 180.0;
+	}
+
+	public static double radToDeg(double v) {
+		return v * 180.0 / Math.PI;
+	}
+
+	// For negative angles, d should be negative, m & s positive.
+	public static double dmsToRad(double d, double m, double s) {
+		if (d >= 0)
+			return (d + m/60 + s/3600) * Math.PI / 180.0;
+		return (d - m/60 - s/3600) * Math.PI / 180.0;
+	}
+
+	// For negative angles, d should be negative, m & s positive.
+	public static double dmsToDeg(double d, double m, double s) {
+		if (d >= 0)
+			return (d + m/60 + s/3600);
+		return (d - m/60 - s/3600);
+	}
+
+	public static double normalizeLatitude(double angle) {
+		if (Double.isInfinite(angle) || Double.isNaN(angle))
+			throw new ProjectionException("Infinite latitude");
+		while (angle > MapMath.HALFPI)
+			angle -= Math.PI;
+		while (angle < -MapMath.HALFPI)
+			angle += Math.PI;
+		return angle;
+//		return Math.IEEEremainder(angle, Math.PI);
+	}
+
+        /**
+         * normalize longitude angle in radians
+         * @param angle
+         * @return
+         */
+	public static double normalizeLongitude(double angle) {
+		if (Double.isInfinite(angle) || Double.isNaN(angle))
+			throw new ProjectionException("Infinite longitude");
+
+                // avoid instable computations with very small numbers: if the
+                // angle is very close to the graticule boundary, return +/-PI.
+                // Bernhard Jenny, May 25 2010.
+                if (Math.abs(angle - Math.PI) < 1e-15) {
+                    return Math.PI;
+                }
+                if (Math.abs(angle + Math.PI) < 1e-15) {
+                    return -Math.PI;
+                }
+                
+                while (angle > Math.PI)
+			angle -= TWOPI;
+		while (angle < -Math.PI)
+			angle += TWOPI;
+		return angle;
+//		return Math.IEEEremainder(angle, Math.PI);
+	}
+	
+	public static double normalizeAngle(double angle) {
+		if (Double.isInfinite(angle) || Double.isNaN(angle))
+			throw new ProjectionException("Infinite angle");
+		while (angle > TWOPI)
+			angle -= TWOPI;
+		while (angle < 0)
+			angle += TWOPI;
+		return angle;
+	}
+	
+/*
+	public static void latLongToXYZ(Point2D.Double ll, Point3D xyz) {
+		double c = Math.cos(ll.y);
+		xyz.x = c * Math.cos(ll.x);
+		xyz.y = c * Math.sin(ll.x);
+		xyz.z = Math.sin(ll.y);
+	}
+
+	public static void xyzToLatLong(Point3D xyz, Point2D.Double ll) {
+		ll.y = MapMath.asin(xyz.z);
+		ll.x = MapMath.atan2(xyz.y, xyz.x);
+	}
+*/
+
+	public static double greatCircleDistance(double lon1, double lat1, double lon2, double lat2 ) {
+		double dlat = Math.sin((lat2-lat1)/2);
+		double dlon = Math.sin((lon2-lon1)/2);
+		double r = Math.sqrt(dlat*dlat + Math.cos(lat1)*Math.cos(lat2)*dlon*dlon);
+		return 2.0 * Math.asin(r);
+	}
+
+	public static double sphericalAzimuth(double lat0, double lon0, double lat, double lon) {
+		double diff = lon - lon0;
+		double coslat = Math.cos(lat);
+
+		return Math.atan2(
+			coslat * Math.sin(diff),
+			(Math.cos(lat0) * Math.sin(lat) -
+			Math.sin(lat0) * coslat * Math.cos(diff))
+		);
+	}
+
+	public static boolean sameSigns(double a, double b) {
+		return a < 0 == b < 0;
+	}
+	
+	public static boolean sameSigns(int a, int b) {
+		return a < 0 == b < 0;
+	}
+	
+	public static double takeSign(double a, double b) {
+		a = Math.abs(a);
+		if (b < 0)
+			return -a;
+		return a;
+	}
+
+	public static int takeSign(int a, int b) {
+		a = Math.abs(a);
+		if (b < 0)
+			return -a;
+		return a;
+	}
+
+	public final static int DONT_INTERSECT = 0;
+	public final static int DO_INTERSECT = 1;
+	public final static int COLLINEAR = 2;
+
+	public static int intersectSegments(Point2D.Double aStart, Point2D.Double aEnd, Point2D.Double bStart, Point2D.Double bEnd, Point2D.Double p) {
+		double a1, a2, b1, b2, c1, c2;
+		double r1, r2, r3, r4;
+		double denom, offset, num;
+
+		a1 = aEnd.y-aStart.y;
+		b1 = aStart.x-aEnd.x;
+		c1 = aEnd.x*aStart.y - aStart.x*aEnd.y;
+		r3 = a1*bStart.x + b1*bStart.y + c1;
+		r4 = a1*bEnd.x + b1*bEnd.y + c1;
+
+		if (r3 != 0 && r4 != 0 && sameSigns(r3, r4))
+			return DONT_INTERSECT;
+
+		a2 = bEnd.y-bStart.y;
+		b2 = bStart.x-bEnd.x;
+		c2 = bEnd.x*bStart.y-bStart.x*bEnd.y;
+		r1 = a2*aStart.x + b2*aStart.y + c2;
+		r2 = a2*aEnd.x + b2*aEnd.y + c2;
+
+		if (r1 != 0 && r2 != 0 && sameSigns(r1, r2))
+			return DONT_INTERSECT;
+
+		denom = a1*b2 - a2*b1;
+		if (denom == 0)
+			return COLLINEAR;
+
+		offset = denom < 0 ? -denom/2 : denom/2;
+
+		num = b1*c2 - b2*c1;
+		p.x = (num < 0 ? num-offset : num+offset) / denom;
+
+		num = a2*c1 - a1*c2;
+		p.y = (num < 0 ? num-offset : num+offset) / denom;
+
+		return DO_INTERSECT;
+	}
+
+	public static double dot(Point2D.Double a, Point2D.Double b) {
+		return a.x*b.x + a.y*b.y;
+	}
+	
+	public static Point2D.Double perpendicular(Point2D.Double a) {
+		return new Point2D.Double(-a.y, a.x);
+	}
+	
+	public static Point2D.Double add(Point2D.Double a, Point2D.Double b) {
+		return new Point2D.Double(a.x+b.x, a.y+b.y);
+	}
+	
+	public static Point2D.Double subtract(Point2D.Double a, Point2D.Double b) {
+		return new Point2D.Double(a.x-b.x, a.y-b.y);
+	}
+	
+	public static Point2D.Double multiply(Point2D.Double a, Point2D.Double b) {
+		return new Point2D.Double(a.x*b.x, a.y*b.y);
+	}
+	
+	public static double cross(Point2D.Double a, Point2D.Double b) {
+		return a.x*b.y - b.x*a.y;
+	}
+
+	public static double cross(double x1, double y1, double x2, double y2) {
+		return x1*y2 - x2*y1;
+	}
+
+	public static void normalize(Point2D.Double a) {
+		double d = distance(a.x, a.y);
+		a.x /= d;
+		a.y /= d;
+	}
+	
+	public static void negate(Point2D.Double a) {
+		a.x = -a.x;
+		a.y = -a.y;
+	}
+	
+	public static double longitudeDistance(double l1, double l2) {
+		return Math.min(
+			Math.abs(l1-l2), 
+			((l1 < 0) ? l1+Math.PI : Math.PI-l1) + ((l2 < 0) ? l2+Math.PI : Math.PI-l2)
+		);
+	}
+
+	public static double geocentricLatitude(double lat, double flatness) {
+		double f = 1.0 - flatness;
+		return Math.atan((f*f) * Math.tan(lat));
+	}
+
+	public static double geographicLatitude(double lat, double flatness) {
+		double f = 1.0 - flatness;
+		return Math.atan(Math.tan(lat) / (f*f));
+	}
+
+	public static double tsfn(double phi, double sinphi, double e) {
+		sinphi *= e;
+		return (Math.tan (.5 * (MapMath.HALFPI - phi)) /
+		   Math.pow((1. - sinphi) / (1. + sinphi), .5 * e));
+	}
+
+	public static double msfn(double sinphi, double cosphi, double es) {
+		return cosphi / Math.sqrt(1.0 - es * sinphi * sinphi);
+	}
+
+	private final static int N_ITER = 15;
+
+	public static double phi2(double ts, double e) {
+		double eccnth, phi, con, dphi;
+		int i;
+
+		eccnth = .5 * e;
+		phi = MapMath.HALFPI - 2. * Math.atan(ts);
+		i = N_ITER;
+		do {
+			con = e * Math.sin(phi);
+			dphi = MapMath.HALFPI - 2. * Math.atan(ts * Math.pow((1. - con) / (1. + con), eccnth)) - phi;
+			phi += dphi;
+		} while (Math.abs(dphi) > 1e-10 && --i != 0);
+		if (i <= 0)
+			throw new ProjectionException();
+		return phi;
+	}
+
+	private final static double C00 = 1.0;
+	private final static double C02 = .25;
+	private final static double C04 = .046875;
+	private final static double C06 = .01953125;
+	private final static double C08 = .01068115234375;
+	private final static double C22 = .75;
+	private final static double C44 = .46875;
+	private final static double C46 = .01302083333333333333;
+	private final static double C48 = .00712076822916666666;
+	private final static double C66 = .36458333333333333333;
+	private final static double C68 = .00569661458333333333;
+	private final static double C88 = .3076171875;
+	private final static int MAX_ITER = 10;
+
+	public static double[] enfn(double es) {
+		double t;
+		double[] en = new double[5];
+		en[0] = C00 - es * (C02 + es * (C04 + es * (C06 + es * C08)));
+		en[1] = es * (C22 - es * (C04 + es * (C06 + es * C08)));
+		en[2] = (t = es * es) * (C44 - es * (C46 + es * C48));
+		en[3] = (t *= es) * (C66 - es * C68);
+		en[4] = t * es * C88;
+		return en;
+	}
+
+	public static double mlfn(double phi, double sphi, double cphi, double[] en) {
+		cphi *= sphi;
+		sphi *= sphi;
+		return en[0] * phi - cphi * (en[1] + sphi*(en[2] + sphi*(en[3] + sphi*en[4])));
+	}
+
+	public static double inv_mlfn(double arg, double es, double[] en) {
+		double s, t, phi, k = 1./(1.-es);
+
+		phi = arg;
+		for (int i = MAX_ITER; i != 0; i--) {
+			s = Math.sin(phi);
+			t = 1. - es * s * s;
+			phi -= t = (mlfn(phi, s, Math.cos(phi), en) - arg) * (t * Math.sqrt(t)) * k;
+			if (Math.abs(t) < 1e-11)
+				return phi;
+		}
+		return phi;
+	}
+
+	private final static double P00 = .33333333333333333333;
+	private final static double P01 = .17222222222222222222;
+	private final static double P02 = .10257936507936507936;
+	private final static double P10 = .06388888888888888888;
+	private final static double P11 = .06640211640211640211;
+	private final static double P20 = .01641501294219154443;
+
+	public static double[] authset(double es) {
+		double t;
+		double[] APA = new double[3];
+		APA[0] = es * P00;
+		t = es * es;
+		APA[0] += t * P01;
+		APA[1] = t * P10;
+		t *= es;
+		APA[0] += t * P02;
+		APA[1] += t * P11;
+		APA[2] = t * P20;
+		return APA;
+	}
+
+	public static double authlat(double beta, double []APA) {
+		double t = beta+beta;
+		return(beta + APA[0] * Math.sin(t) + APA[1] * Math.sin(t+t) + APA[2] * Math.sin(t+t+t));
+	}
+	
+	public static double qsfn(double sinphi, double e, double one_es) {
+		double con;
+
+		if (e >= 1.0e-7) {
+			con = e * sinphi;
+			return (one_es * (sinphi / (1. - con * con) -
+			   (.5 / e) * Math.log ((1. - con) / (1. + con))));
+		} else
+			return (sinphi + sinphi);
+	}
+
+	/*
+	 * Java translation of "Nice Numbers for Graph Labels"
+	 * by Paul Heckbert
+	 * from "Graphics Gems", Academic Press, 1990
+	 */
+	public static double niceNumber(double x, boolean round) {
+		int expv;				/* exponent of x */
+		double f;				/* fractional part of x */
+		double nf;				/* nice, rounded fraction */
+
+		expv = (int)Math.floor(Math.log(x) / Math.log(10));
+		f = x/Math.pow(10., expv);		/* between 1 and 10 */
+		if (round) {
+			if (f < 1.5)
+				nf = 1.;
+			else if (f < 3.)
+				nf = 2.;
+			else if (f < 7.)
+				nf = 5.;
+			else
+				nf = 10.;
+		} else if (f <= 1.)
+			nf = 1.;
+		else if (f <= 2.)
+			nf = 2.;
+		else if (f <= 5.)
+			nf = 5.;
+		else
+			nf = 10.;
+		return nf*Math.pow(10., expv);
+	}
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Unit.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Unit.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Unit.java	(revision 23351)
@@ -0,0 +1,96 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map;
+
+import java.io.*;
+import java.text.*;
+
+public class Unit implements Serializable {
+
+	static final long serialVersionUID = -6704954923429734628L;
+	
+	public final static int ANGLE_UNIT = 0;
+	public final static int LENGTH_UNIT = 1;
+	public final static int AREA_UNIT = 2;
+	public final static int VOLUME_UNIT = 3;
+	
+	public String name, plural, abbreviation;
+	public double value;
+	public static NumberFormat format;
+	
+	static {
+		format = NumberFormat.getNumberInstance();
+		format.setMaximumFractionDigits(2);
+		format.setGroupingUsed(false);
+	}
+	
+	public Unit(String name, String plural, String abbreviation, double value) {
+		this.name = name;
+		this.plural = plural;
+		this.abbreviation = abbreviation;
+		this.value = value;
+	}
+
+	public double toBase(double n) {
+		return n * value;
+	}
+
+	public double fromBase(double n) {
+		return n / value;
+	}
+	
+	public double parse(String s) throws NumberFormatException {
+		try {
+			return format.parse(s).doubleValue();
+		}
+		catch (java.text.ParseException e) {
+			throw new NumberFormatException(e.getMessage());
+		}
+	}
+	
+	public String format(double n) {
+		return format.format(n)+" "+abbreviation;
+	}
+	
+	public String format(double n, boolean abbrev) {
+		if (abbrev)
+			return format.format(n)+" "+abbreviation;
+		return format.format(n);
+	}
+	
+	public String format(double x, double y, boolean abbrev) {
+		if (abbrev)
+			return format.format(x)+"/"+format.format(y)+" "+abbreviation;
+		return format.format(x)+"/"+format.format(y);
+	}
+
+	public String format(double x, double y) {
+		return format(x, y, true);
+	}
+
+	public String toString() {
+		return plural;
+	}
+
+	public boolean equals(Object o) {
+		if (o instanceof Unit) {
+			return ((Unit)o).value == value;
+		}
+		return false;
+	}
+
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Units.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Units.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/Units.java	(revision 23351)
@@ -0,0 +1,82 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map;
+
+import java.io.*;
+import java.text.*;
+
+public class Units {
+
+	// Angular units
+	public final static Unit DEGREES = new DegreeUnit();
+	public final static Unit RADIANS = new Unit("radian", "radians", "rad", Math.toDegrees(1));
+	public final static Unit ARC_MINUTES = new Unit("arc minute", "arc minutes", "min", 1/60.0);
+	public final static Unit ARC_SECONDS = new Unit("arc second", "arc seconds", "sec", 1/3600.0);
+
+	// Distance units
+	
+	// Metric units
+	public final static Unit KILOMETRES = new Unit("kilometre", "kilometres", "km", 1000);
+	public final static Unit METRES = new Unit("metre", "metres", "m", 1);
+	public final static Unit DECIMETRES = new Unit("decimetre", "decimetres", "dm", 0.1);
+	public final static Unit CENTIMETRES = new Unit("centimetre", "centimetres", "cm", 0.01);
+	public final static Unit MILLIMETRES = new Unit("millimetre", "millimetres", "mm", 0.001);
+
+	// International units
+	public final static Unit NAUTICAL_MILES = new Unit("nautical mile", "nautical miles", "kmi", 1852);
+	public final static Unit MILES = new Unit("mile", "miles", "mi", 1609.344);
+	public final static Unit CHAINS = new Unit("chain", "chains", "ch", 20.1168);
+	public final static Unit YARDS = new Unit("yard", "yards", "yd", 0.9144);
+	public final static Unit FEET = new Unit("foot", "feet", "ft", 0.3048);
+	public final static Unit INCHES = new Unit("inch", "inches", "in", 0.0254);
+
+	// U.S. units
+	public final static Unit US_MILES = new Unit("U.S. mile", "U.S. miles", "us-mi", 1609.347218694437);
+	public final static Unit US_CHAINS = new Unit("U.S. chain", "U.S. chains", "us-ch", 20.11684023368047);
+	public final static Unit US_YARDS = new Unit("U.S. yard", "U.S. yards", "us-yd", 0.914401828803658);
+	public final static Unit US_FEET = new Unit("U.S. foot", "U.S. feet", "us-ft", 0.304800609601219);
+	public final static Unit US_INCHES = new Unit("U.S. inch", "U.S. inches", "us-in", 1.0/39.37);
+
+	// Miscellaneous units
+	public final static Unit FATHOMS = new Unit("fathom", "fathoms", "fath", 1.8288);
+	public final static Unit LINKS = new Unit("link", "links", "link", 0.201168);
+
+	public final static Unit POINTS = new Unit("point", "points", "point", 0.0254/72.27);
+
+	public static Unit[] units = {
+		DEGREES,
+		KILOMETRES, METRES, DECIMETRES, CENTIMETRES, MILLIMETRES,
+		MILES, YARDS, FEET, INCHES,
+		US_MILES, US_YARDS, US_FEET, US_INCHES,
+		NAUTICAL_MILES
+	};
+
+	public static Unit findUnits(String name) {
+		for (int i = 0; i < units.length; i++) {
+			if (name.equals(units[i].name) || name.equals(units[i].plural) || name.equals(units[i].abbreviation))
+				return units[i];
+		}
+		return METRES;
+	}
+
+	public static double convert(double value, Unit from, Unit to) {
+		if (from == to)
+			return value;
+		return to.fromBase(from.toBase(value));
+	}
+
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/AzimuthalProjection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/AzimuthalProjection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/AzimuthalProjection.java	(revision 23351)
@@ -0,0 +1,75 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map.proj;
+
+import java.awt.*;
+import java.awt.geom.*;
+import com.jhlabs.map.*;
+
+/**
+ * The superclass for all azimuthal map projections
+ */
+public class AzimuthalProjection extends Projection {
+
+	public final static int NORTH_POLE = 1;
+	public final static int SOUTH_POLE = 2;
+	public final static int EQUATOR = 3;
+	public final static int OBLIQUE = 4;
+	
+	protected int mode;
+	protected double sinphi0, cosphi0;
+	private double mapRadius = 90.0;
+	
+	public AzimuthalProjection() {
+		this( 0,0);//Math.toRadians(45.0), Math.toRadians(45.0) );
+	}
+
+	public AzimuthalProjection(double projectionLatitude, double projectionLongitude) {
+		this.projectionLatitude = projectionLatitude;
+		this.projectionLongitude = projectionLongitude;
+		initialize();
+	}
+	
+	public void initialize() {
+		super.initialize();
+		if (Math.abs(Math.abs(projectionLatitude) - MapMath.HALFPI) < EPS10)
+			mode = projectionLatitude < 0. ? SOUTH_POLE : NORTH_POLE;
+		else if (Math.abs(projectionLatitude) > EPS10) {
+			mode = OBLIQUE;
+			sinphi0 = Math.sin(projectionLatitude);
+			cosphi0 = Math.cos(projectionLatitude);
+		} else
+			mode = EQUATOR;
+	}
+
+	public boolean inside(double lon, double lat) {
+		return MapMath.greatCircleDistance( Math.toRadians(lon), Math.toRadians(lat), projectionLongitude, projectionLatitude) < Math.toRadians(mapRadius);
+	}
+
+	/**
+	 * Set the map radius (in degrees). 180 shows a hemisphere, 360 shows the whole globe.
+	 */
+	public void setMapRadius(double mapRadius) {
+		this.mapRadius = mapRadius;
+	}
+
+	public double getMapRadius() {
+		return mapRadius;
+	}
+
+}
+
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ConicProjection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ConicProjection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ConicProjection.java	(revision 23351)
@@ -0,0 +1,86 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map.proj;
+
+import java.awt.*;
+
+/**
+ * The superclass for all Conic projections.
+ *
+ * Bernhard Jenny, 17 September 2010:
+ * Moved projectionLatitude1 and projectionLatitude2 from super class to
+ * ConicProjection, as these are specific to conics.
+ */
+public class ConicProjection extends Projection {
+
+    /**
+     * Standard parallel 1 (for projections which use it)
+     */
+    protected double projectionLatitude1 = 0.0;
+    /**
+     * Standard parallel 2 (for projections which use it)
+     */
+    protected double projectionLatitude2 = 0.0;
+
+	public String toString() {
+		return "Conic";
+	}
+
+        /**
+     * Set the projection latitude in radians.
+     */
+    public void setProjectionLatitude1(double projectionLatitude1) {
+        this.projectionLatitude1 = projectionLatitude1;
+    }
+
+    public double getProjectionLatitude1() {
+        return projectionLatitude1;
+    }
+
+    /**
+     * Set the projection latitude in degrees.
+     */
+    public void setProjectionLatitude1Degrees(double projectionLatitude1) {
+        this.projectionLatitude1 = DTR * projectionLatitude1;
+    }
+
+    public double getProjectionLatitude1Degrees() {
+        return projectionLatitude1 * RTD;
+    }
+
+    /**
+     * Set the projection latitude in radians.
+     */
+    public void setProjectionLatitude2(double projectionLatitude2) {
+        this.projectionLatitude2 = projectionLatitude2;
+    }
+
+    public double getProjectionLatitude2() {
+        return projectionLatitude2;
+    }
+
+    /**
+     * Set the projection latitude in degrees.
+     */
+    public void setProjectionLatitude2Degrees(double projectionLatitude2) {
+        this.projectionLatitude2 = DTR * projectionLatitude2;
+    }
+
+    public double getProjectionLatitude2Degrees() {
+        return projectionLatitude2 * RTD;
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/CylindricalProjection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/CylindricalProjection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/CylindricalProjection.java	(revision 23351)
@@ -0,0 +1,34 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+/**
+ * Rremoved long unrelated commented method for geometrical path splitting
+ * by Bernhard Jenny, May 18 2010.
+ */
+package com.jhlabs.map.proj;
+
+/**
+ * The superclass for all cylindrical projections.
+ */
+public class CylindricalProjection extends Projection {
+
+    public boolean isRectilinear() {
+        return true;
+    }
+
+    public String toString() {
+        return "Cylindrical";
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/MercatorProjection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/MercatorProjection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/MercatorProjection.java	(revision 23351)
@@ -0,0 +1,76 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+/*
+ * This file was semi-automatically converted from the public-domain USGS PROJ source.
+ */
+/**
+ * Added isConformal method, removed isRectilinear (duplicate of super class)
+ * by Bernhard Jenny, June 26, 2008.
+ */
+package com.jhlabs.map.proj;
+
+import java.awt.geom.*;
+import com.jhlabs.map.*;
+
+public class MercatorProjection extends CylindricalProjection {
+
+    public MercatorProjection() {
+        minLatitude = MapMath.degToRad(-85);
+        maxLatitude = MapMath.degToRad(85);
+    }
+
+    public Point2D.Double project(double lam, double phi, Point2D.Double out) {
+        if (spherical) {
+            out.x = scaleFactor * lam;
+            out.y = scaleFactor * Math.log(Math.tan(MapMath.QUARTERPI + 0.5 * phi));
+        } else {
+            out.x = scaleFactor * lam;
+            out.y = -scaleFactor * Math.log(MapMath.tsfn(phi, Math.sin(phi), e));
+        }
+        return out;
+    }
+
+    public Point2D.Double projectInverse(double x, double y, Point2D.Double out) {
+        if (spherical) {
+            out.y = MapMath.HALFPI - 2. * Math.atan(Math.exp(-y / scaleFactor));
+            out.x = x / scaleFactor;
+        } else {
+            out.y = MapMath.phi2(Math.exp(-y / scaleFactor), e);
+            out.x = x / scaleFactor;
+        }
+        return out;
+    }
+
+    public boolean hasInverse() {
+        return true;
+    }
+
+    public boolean isConformal() {
+        return true;
+    }
+
+    /**
+     * Returns the ESPG code for this projection, or 0 if unknown.
+     */
+    public int getEPSGCode() {
+        return 9804;
+    }
+
+    public String toString() {
+        return "Mercator";
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/OrteliusProjection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/OrteliusProjection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/OrteliusProjection.java	(revision 23351)
@@ -0,0 +1,71 @@
+/*
+Copyright 2010 Bernhard Jenny
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+package com.jhlabs.map.proj;
+
+import com.jhlabs.map.MapMath;
+import java.awt.geom.Point2D;
+
+/**
+ * Bacon Globular projection.
+ * Code from proj4.
+ * @author Bernhard Jenny, Institute of Cartography, ETH Zurich
+ */
+public class OrteliusProjection extends Projection {
+
+    private static final double HLFPI2 = 2.46740110027233965467;
+    private static final double EPS = 1e-10;
+
+    public OrteliusProjection() {
+        minLongitude = Math.toRadians(-90);
+        maxLongitude = Math.toRadians(90);
+        initialize();
+    }
+
+    public Point2D.Double project(double lplam, double lpphi, Point2D.Double out) {
+
+        out.y = lpphi;
+        final double ax = Math.abs(lplam);
+        if (ax >= EPS) {
+            if (ax >= MapMath.HALFPI) {
+                out.x = Math.sqrt(HLFPI2 - lpphi * lpphi + EPS) + ax - MapMath.HALFPI;
+            } else {
+                final double f = 0.5 * (HLFPI2 / ax + ax);
+                out.x = ax - f + Math.sqrt(f * f - out.y * out.y);
+            }
+            if (lplam < 0.) {
+                out.x = -out.x;
+            }
+        } else {
+            out.x = 0.;
+        }
+        return out;
+    }
+
+    @Override
+    public Point2D.Double projectInverse(double x, double y, Point2D.Double out) {
+        binarySearchInverse(x, y, out);
+        return out;
+    }
+
+    @Override
+    public boolean hasInverse() {
+        return true;
+    }
+
+    public String toString() {
+        return "Ortelius Oval";
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/Projection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/Projection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/Projection.java	(revision 23351)
@@ -0,0 +1,851 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+package com.jhlabs.map.proj;
+
+import java.awt.geom.*;
+import com.jhlabs.map.*;
+import java.io.Serializable;
+
+/**
+ * The superclass for all map projections
+ *
+ * Changes:
+ * Added Serializable interface, added abstract keyword, added
+ * binarySearchInverse, added transform and inverseTransform with lon/lat
+ * as doubles.
+ * Bernhard Jenny, 18 May 2010
+ */
+public abstract class Projection implements Cloneable, Serializable {
+
+    /**
+     * The minimum latitude of the bounds of this projection
+     */
+    protected double minLatitude = -Math.PI / 2;
+    /**
+     * The minimum longitude of the bounds of this projection. This is relative to the projection centre.
+     */
+    protected double minLongitude = -Math.PI;
+    /**
+     * The maximum latitude of the bounds of this projection
+     */
+    protected double maxLatitude = Math.PI / 2;
+    /**
+     * The maximum longitude of the bounds of this projection. This is relative to the projection centre.
+     */
+    protected double maxLongitude = Math.PI;
+    /**
+     * The latitude of the centre of projection
+     */
+    protected double projectionLatitude = 0.0;
+    /**
+     * The longitude of the centre of projection
+     */
+    protected double projectionLongitude = 0.0;
+    
+    /**
+     * The projection scale factor
+     */
+    protected double scaleFactor = 1.0;
+    /**
+     * The false Easting of this projection
+     */
+    protected double falseEasting = 0;
+    /**
+     * The false Northing of this projection
+     */
+    protected double falseNorthing = 0;
+    /**
+     * The latitude of true scale. Only used by specific projections.
+     */
+    protected double trueScaleLatitude = 0.0;
+    /**
+     * The equator radius
+     */
+    protected double a = 0;
+    /**
+     * The eccentricity
+     */
+    protected double e = 0;
+    /**
+     * The eccentricity squared
+     */
+    protected double es = 0;
+    /**
+     * 1-(eccentricity squared)
+     */
+    protected double one_es = 0;
+    /**
+     * 1/(1-(eccentricity squared))
+     */
+    protected double rone_es = 0;
+    /**
+     * The ellipsoid used by this projection
+     */
+    protected Ellipsoid ellipsoid;
+    /**
+     * True if this projection is using a sphere (es == 0)
+     */
+    protected boolean spherical;
+    /**
+     * True if this projection is geocentric
+     */
+    protected boolean geocentric;
+    /**
+     * The name of this projection
+     */
+    protected String name = null;
+    /**
+     * Conversion factor from metres to whatever units the projection uses.
+     */
+    protected double fromMetres = 1;
+    /**
+     * The total scale factor = Earth radius * units
+     */
+    private double totalScale = 0;
+    /**
+     * falseEasting, adjusted to the appropriate units using fromMetres
+     */
+    private double totalFalseEasting = 0;
+    /**
+     * falseNorthing, adjusted to the appropriate units using fromMetres
+     */
+    private double totalFalseNorthing = 0;
+    // Some useful constants
+    protected final static double EPS10 = 1e-10;
+    protected final static double RTD = 180.0 / Math.PI;
+    protected final static double DTR = Math.PI / 180.0;
+
+    protected Projection() {
+        setEllipsoid(Ellipsoid.SPHERE);
+    }
+
+    public Object clone() {
+        try {
+            Projection e = (Projection) super.clone();
+            return e;
+        } catch (CloneNotSupportedException e) {
+            throw new InternalError();
+        }
+    }
+
+    /**
+     * Project a lat/long point (in degrees), producing a result in metres
+     */
+    public Point2D.Double transform(Point2D.Double src, Point2D.Double dst) {
+        double x = src.x * DTR;
+        if (projectionLongitude != 0) {
+            x = MapMath.normalizeLongitude(x - projectionLongitude);
+        }
+        project(x, src.y * DTR, dst);
+        dst.x = totalScale * dst.x + totalFalseEasting;
+        dst.y = totalScale * dst.y + totalFalseNorthing;
+        return dst;
+    }
+
+    /**
+     * Project a lon/lat point (in degrees), producing a result in metres.
+     * Important: unlike the other variations of tansform, this implementation
+     * always normalizes the longitude, even if projectionLongitude is 0. This
+     * is useful for projecting line features crossing +/180 degree of longitude.
+     * Bernhard Jenny, May 2010.
+     */
+    public final Point2D.Double transform(double lon, double lat, Point2D.Double dst) {
+        lon = MapMath.normalizeLongitude(lon * DTR - projectionLongitude);
+        project(lon, lat * DTR, dst);
+        dst.x = totalScale * dst.x + totalFalseEasting;
+        dst.y = totalScale * dst.y + totalFalseNorthing;
+        return dst;
+    }
+
+    /**
+     * Project a lat/long point, producing a result in metres
+     */
+    public Point2D.Double transformRadians(Point2D.Double src, Point2D.Double dst) {
+        double x = src.x;
+        if (projectionLongitude != 0) {
+            x = MapMath.normalizeLongitude(x - projectionLongitude);
+        }
+        project(x, src.y, dst);
+        dst.x = totalScale * dst.x + totalFalseEasting;
+        dst.y = totalScale * dst.y + totalFalseNorthing;
+        return dst;
+    }
+
+    /**
+     * Project a lon/lat point (in degrees), producing a result in metres.
+     * Important: unlike the other variations of tansform, this implementation
+     * always normalizes the longitude, even if projectionLongitude is 0. This
+     * is useful for projecting line features crossing +/180 degree of longitude.
+     * Bernhard Jenny, May 2010.
+     */
+    public final Point2D.Double transformRadians(double lon, double lat, Point2D.Double dst) {
+        lon = MapMath.normalizeLongitude(lon - projectionLongitude);
+        project(lon, lat, dst);
+        dst.x = totalScale * dst.x + totalFalseEasting;
+        dst.y = totalScale * dst.y + totalFalseNorthing;
+        return dst;
+    }
+
+    /**
+     * The method which actually does the projection. This should be overridden
+     * for all projections.
+     * @param x Longitude in radians.
+     * @param y Latitude in radians.
+     * @param dst The projected point.
+     * @return The projected point, identical to parameter dst.
+     */
+    public Point2D.Double project(double x, double y, Point2D.Double dst) {
+        dst.x = x;
+        dst.y = y;
+        return dst;
+    }
+
+    /**
+     * Project a number of lat/long points (in degrees), producing a result in metres
+     */
+    public void transform(double[] srcPoints, int srcOffset, double[] dstPoints, int dstOffset, int numPoints) {
+        Point2D.Double in = new Point2D.Double();
+        Point2D.Double out = new Point2D.Double();
+        for (int i = 0; i < numPoints; i++) {
+            in.x = srcPoints[srcOffset++];
+            in.y = srcPoints[srcOffset++];
+            transform(in, out);
+            dstPoints[dstOffset++] = out.x;
+            dstPoints[dstOffset++] = out.y;
+        }
+    }
+
+    /**
+     * Project a number of lat/long points (in radians), producing a result in metres
+     */
+    public void transformRadians(double[] srcPoints, int srcOffset, double[] dstPoints, int dstOffset, int numPoints) {
+        Point2D.Double in = new Point2D.Double();
+        Point2D.Double out = new Point2D.Double();
+        for (int i = 0; i < numPoints; i++) {
+            in.x = srcPoints[srcOffset++];
+            in.y = srcPoints[srcOffset++];
+            transform(in, out);
+            dstPoints[dstOffset++] = out.x;
+            dstPoints[dstOffset++] = out.y;
+        }
+    }
+
+    /**
+     * Inverse-project a point (in metres), producing a lat/long result in degrees
+     */
+    public Point2D.Double inverseTransform(Point2D.Double src, Point2D.Double dst) {
+        double x = (src.x - totalFalseEasting) / totalScale;
+        double y = (src.y - totalFalseNorthing) / totalScale;
+        projectInverse(x, y, dst);
+        if (dst.x < -Math.PI) {
+            dst.x = -Math.PI;
+        } else if (dst.x > Math.PI) {
+            dst.x = Math.PI;
+        }
+        if (projectionLongitude != 0) {
+            dst.x = MapMath.normalizeLongitude(dst.x + projectionLongitude);
+        }
+        dst.x *= RTD;
+        dst.y *= RTD;
+        return dst;
+    }
+
+    /**
+     * Inverse-project a point (in metres), producing a lat/long result in radians
+     */
+    public Point2D.Double inverseTransformRadians(Point2D.Double src, Point2D.Double dst) {
+        double x = (src.x - totalFalseEasting) / totalScale;
+        double y = (src.y - totalFalseNorthing) / totalScale;
+        projectInverse(x, y, dst);
+        if (dst.x < -Math.PI) {
+            dst.x = -Math.PI;
+        } else if (dst.x > Math.PI) {
+            dst.x = Math.PI;
+        }
+        if (projectionLongitude != 0) {
+            dst.x = MapMath.normalizeLongitude(dst.x + projectionLongitude);
+        }
+        return dst;
+    }
+
+    /**
+     * Inverse-project a point (in meters), producing a lat/long result in radians.
+     * Added by Bernhard Jenny, May 2007.
+     */
+    public void inverseTransformRadians(double srcX, double srcY, Point2D.Double dst) {
+        double x = (srcX - totalFalseEasting) / totalScale;
+        double y = (srcY - totalFalseNorthing) / totalScale;
+        projectInverse(x, y, dst);
+        if (dst.x < -Math.PI) {
+            dst.x = -Math.PI;
+        } else if (dst.x > Math.PI) {
+            dst.x = Math.PI;
+        }
+        if (projectionLongitude != 0) {
+            dst.x = MapMath.normalizeLongitude(dst.x + projectionLongitude);
+        }
+    }
+
+
+    /**
+     * The method which actually does the inverse projection. This should be overridden for all projections.
+     */
+    public Point2D.Double projectInverse(double x, double y, Point2D.Double dst) {
+        dst.x = x;
+        dst.y = y;
+        return dst;
+    }
+
+    /**
+     * Inverse-project a number of points (in metres), producing a lat/long result in degrees
+     */
+    public void inverseTransform(double[] srcPoints, int srcOffset, double[] dstPoints, int dstOffset, int numPoints) {
+        Point2D.Double in = new Point2D.Double();
+        Point2D.Double out = new Point2D.Double();
+        for (int i = 0; i < numPoints; i++) {
+            in.x = srcPoints[srcOffset++];
+            in.y = srcPoints[srcOffset++];
+            inverseTransform(in, out);
+            dstPoints[dstOffset++] = out.x;
+            dstPoints[dstOffset++] = out.y;
+        }
+    }
+
+    /**
+     * Inverse-project a number of points (in metres), producing a lat/long result in radians
+     */
+    public void inverseTransformRadians(double[] srcPoints, int srcOffset, double[] dstPoints, int dstOffset, int numPoints) {
+        Point2D.Double in = new Point2D.Double();
+        Point2D.Double out = new Point2D.Double();
+        for (int i = 0; i < numPoints; i++) {
+            in.x = srcPoints[srcOffset++];
+            in.y = srcPoints[srcOffset++];
+            inverseTransformRadians(in, out);
+            dstPoints[dstOffset++] = out.x;
+            dstPoints[dstOffset++] = out.y;
+        }
+    }
+
+    /**
+     * Finds the smallest lat/long rectangle wholly inside the given view rectangle.
+     * This is only a rough estimate.
+     */
+    public Rectangle2D inverseTransform(Rectangle2D r) {
+        Point2D.Double in = new Point2D.Double();
+        Point2D.Double out = new Point2D.Double();
+        Rectangle2D bounds = null;
+        if (isRectilinear()) {
+            for (int ix = 0; ix < 2; ix++) {
+                double x = r.getX() + r.getWidth() * ix;
+                for (int iy = 0; iy < 2; iy++) {
+                    double y = r.getY() + r.getHeight() * iy;
+                    in.x = x;
+                    in.y = y;
+                    inverseTransform(in, out);
+                    if (ix == 0 && iy == 0) {
+                        bounds = new Rectangle2D.Double(out.x, out.y, 0, 0);
+                    } else {
+                        bounds.add(out.x, out.y);
+                    }
+                }
+            }
+        } else {
+            for (int ix = 0; ix < 7; ix++) {
+                double x = r.getX() + r.getWidth() * ix / 6;
+                for (int iy = 0; iy < 7; iy++) {
+                    double y = r.getY() + r.getHeight() * iy / 6;
+                    in.x = x;
+                    in.y = y;
+                    inverseTransform(in, out);
+                    if (ix == 0 && iy == 0) {
+                        bounds = new Rectangle2D.Double(out.x, out.y, 0, 0);
+                    } else {
+                        bounds.add(out.x, out.y);
+                    }
+                }
+            }
+        }
+        return bounds;
+    }
+
+    public static void main (String[] args) {
+        Projection p = new OrteliusProjection();
+        Ellipsoid unarySphere = new Ellipsoid(null, 1, 0, null);
+        p.setEllipsoid(unarySphere);
+        p.initialize();
+        p.testBinarySearchInverse();
+    }
+
+    public void testBinarySearchInverse() {
+        Point2D.Double pt1 = new Point2D.Double();
+        Point2D.Double pt2 = new Point2D.Double();
+
+        for (int lon = -180; lon <= 180; lon++) {
+            for (int lat = -89; lat < 90; lat++) {
+                if (!inside(lon, lat)) {
+                    continue;
+                }
+                transform(lon, lat, pt1);
+                binarySearchInverse(pt1.x, pt1.y, 
+                        Math.toRadians(0),
+                        Math.toRadians(0),
+                        pt2);
+                double lon2 = Math.toDegrees(pt2.x);
+                double lat2 = Math.toDegrees(pt2.y);
+                double d = Math.hypot(lon - lon2, lat - lat2);
+                if (d > 1e-6) {
+                    System.out.println(lon + "/" + lat + ": " + d);
+                }
+            }
+        }
+    }
+
+    /**
+     * Compute the inverse projection by a binary search.
+     * Use this method carefully! It is slow and only an approximation for
+     * projections that do not provide their own projectInverse method.
+     * Added by Bernhard Jenny, 18 May 2010.
+     * @param x The projected x coordinate relative to the unary sphere.
+     * @param y The projected y coordinate relative to the unary sphere.
+     * @param lp A point that will receive the result.
+     */
+    protected void binarySearchInverse(double x, double y, Point2D.Double lp) {
+        binarySearchInverse(x, y, 0, 0, lp);
+    }
+
+    /**
+     * Compute the inverse projection by a binary search.
+     * Use this method carfully! It is slow and only an approximation for
+     * projections that do not provide their own projectInverse method.
+     * Added by Bernhard Jenny, 18 May 2010.
+     * @param x The projected x coordinate relative to the unary sphere.
+     * @param y The projected y coordinate relative to the unary sphere.
+     * @param lon An approximation of the longitude in radians.
+     * @param lat An approximation of the latitude in radians.
+     * @param lp A point that will receive the result.
+     */
+    protected void binarySearchInverse(double x, double y,
+            double lon, double lat, Point2D.Double lp) {
+
+        // tolerance for approximating longitude and latitude
+        final double TOL = 1e-9; // less than a hundreth of a second
+
+        // maximum number of loops
+        final int MAX_LOOP = 1000;
+
+        int counter = 0;
+        double dx, dy;
+        do {
+            // forward projection
+            this.project(lon, lat, lp);
+            dx = x - lp.x; // horizontal difference in projected coordinates
+            dy = y - lp.y; // vertical difference in projected coordinates
+            lon += dx * 0.5; // add half of the horizontal difference to the longitude
+            lat += dy * 0.5; // add half of the vertical difference to the latitude
+
+            // stop if it is not converging
+            if (counter++ == MAX_LOOP) {
+                lon = Double.NaN;
+                lat = Double.NaN;
+                break;
+            }
+
+            // stop when difference is small enough
+        } while (dx > TOL || dx < -TOL || dy > TOL || dy < -TOL);
+
+        lp.x = lon;
+        lp.y = lat;
+    }
+    
+    /**
+     * Transform a bounding box. This is only a rough estimate.
+     */
+    public Rectangle2D transform(Rectangle2D r) {
+        Point2D.Double in = new Point2D.Double();
+        Point2D.Double out = new Point2D.Double();
+        Rectangle2D bounds = null;
+        if (isRectilinear()) {
+            for (int ix = 0; ix < 2; ix++) {
+                double x = r.getX() + r.getWidth() * ix;
+                for (int iy = 0; iy < 2; iy++) {
+                    double y = r.getY() + r.getHeight() * iy;
+                    in.x = x;
+                    in.y = y;
+                    transform(in, out);
+                    if (ix == 0 && iy == 0) {
+                        bounds = new Rectangle2D.Double(out.x, out.y, 0, 0);
+                    } else {
+                        bounds.add(out.x, out.y);
+                    }
+                }
+            }
+        } else {
+            for (int ix = 0; ix < 7; ix++) {
+                double x = r.getX() + r.getWidth() * ix / 6;
+                for (int iy = 0; iy < 7; iy++) {
+                    double y = r.getY() + r.getHeight() * iy / 6;
+                    in.x = x;
+                    in.y = y;
+                    transform(in, out);
+                    if (ix == 0 && iy == 0) {
+                        bounds = new Rectangle2D.Double(out.x, out.y, 0, 0);
+                    } else {
+                        bounds.add(out.x, out.y);
+                    }
+                }
+            }
+        }
+        return bounds;
+    }
+
+    /**
+     * Returns true if this projection is conformal
+     */
+    public boolean isConformal() {
+        return false;
+    }
+
+    /**
+     * Returns true if this projection is equal area
+     */
+    public boolean isEqualArea() {
+        return false;
+    }
+
+    /**
+     * Returns true if this projection has an inverse
+     */
+    public boolean hasInverse() {
+        return false;
+    }
+
+    /**
+     * Returns true if lat/long lines form a rectangular grid for this projection.
+     * This is generally only the case for cylindrical projections, but not
+     * for oblique cylindrical projections.
+     */
+    public boolean isRectilinear() {
+        return false;
+    }
+
+    /**
+     * Returns true if latitude lines are parallel for this projection
+     */
+    public boolean parallelsAreParallel() {
+        return isRectilinear();
+    }
+
+    /**
+     * Returns true if the given lat/lon point is visible in this projection.
+     * @param x longitude in degrees.
+     * @param y latitude in degrees.
+     * @return
+     */
+    public boolean inside(double lon, double lat) {
+        lon = MapMath.normalizeLongitude(lon * DTR - projectionLongitude);
+        lat *= DTR;
+        return minLongitude <= lon && lon <= maxLongitude && minLatitude <= lat && lat <= maxLatitude;
+    }
+
+    /**
+     * Set the name of this projection.
+     */
+    public void setName(String name) {
+        this.name = name;
+    }
+
+    public String getName() {
+        if (name != null) {
+            return name;
+        }
+        return toString();
+    }
+
+    /**
+     * Returns a human readable description of this projection in telegram style.
+     * @return
+     */
+    public String getProjectionDescription() {
+        StringBuilder sb = new StringBuilder();
+
+        // projection type
+        if (this instanceof CylindricalProjection) {
+            sb.append("cylindrical ");
+        }
+        if (this instanceof ConicProjection) {
+            sb.append("conic ");
+        }
+        if (this instanceof PseudoCylindricalProjection) {
+            sb.append("pseudo cylindrical ");
+        }
+        if (this instanceof AzimuthalProjection) {
+            sb.append("azimuthal ");
+        }
+
+        // distortion
+        if (this.isConformal()) {
+            sb.append("conformal");
+        }
+        if (this.isEqualArea()) {
+            sb.append("equal-area");
+        }
+        return sb.toString();
+    }
+
+    /**
+     * Get a string which describes this projection in PROJ.4 format.
+     */
+    public String getPROJ4Description() {
+        AngleFormat format = new AngleFormat(AngleFormat.ddmmssPattern, false);
+        StringBuffer sb = new StringBuffer();
+        sb.append(
+                "+proj=" + getName()
+                + " +a=" + a);
+        if (es != 0) {
+            sb.append(" +es=" + es);
+        }
+        sb.append(" +lon_0=");
+        format.format(projectionLongitude, sb, null);
+        sb.append(" +lat_0=");
+        format.format(projectionLatitude, sb, null);
+        if (falseEasting != 1) {
+            sb.append(" +x_0=" + falseEasting);
+        }
+        if (falseNorthing != 1) {
+            sb.append(" +y_0=" + falseNorthing);
+        }
+        if (scaleFactor != 1) {
+            sb.append(" +k=" + scaleFactor);
+        }
+        if (fromMetres != 1) {
+            sb.append(" +fr_meters=" + fromMetres);
+        }
+        return sb.toString();
+    }
+
+    public String toString() {
+        return "None";
+    }
+
+    /**
+     * Set the minimum latitude. This is only used for Shape clipping and doesn't affect projection.
+     */
+    public void setMinLatitude(double minLatitude) {
+        this.minLatitude = minLatitude;
+    }
+
+    public double getMinLatitude() {
+        return minLatitude;
+    }
+
+    /**
+     * Set the maximum latitude. This is only used for Shape clipping and doesn't affect projection.
+     */
+    public void setMaxLatitude(double maxLatitude) {
+        this.maxLatitude = maxLatitude;
+    }
+
+    public double getMaxLatitude() {
+        return maxLatitude;
+    }
+
+    public double getMaxLatitudeDegrees() {
+        return maxLatitude * RTD;
+    }
+
+    public double getMinLatitudeDegrees() {
+        return minLatitude * RTD;
+    }
+
+    public void setMinLongitude(double minLongitude) {
+        this.minLongitude = minLongitude;
+    }
+
+    public double getMinLongitude() {
+        return minLongitude;
+    }
+
+    public void setMinLongitudeDegrees(double minLongitude) {
+        this.minLongitude = DTR * minLongitude;
+    }
+
+    public double getMinLongitudeDegrees() {
+        return minLongitude * RTD;
+    }
+
+    public void setMaxLongitude(double maxLongitude) {
+        this.maxLongitude = maxLongitude;
+    }
+
+    public double getMaxLongitude() {
+        return maxLongitude;
+    }
+
+    public void setMaxLongitudeDegrees(double maxLongitude) {
+        this.maxLongitude = DTR * maxLongitude;
+    }
+
+    public double getMaxLongitudeDegrees() {
+        return maxLongitude * RTD;
+    }
+
+    /**
+     * Set the projection latitude in radians.
+     */
+    public void setProjectionLatitude(double projectionLatitude) {
+        this.projectionLatitude = projectionLatitude;
+    }
+
+    public double getProjectionLatitude() {
+        return projectionLatitude;
+    }
+
+    /**
+     * Set the projection latitude in degrees.
+     */
+    public void setProjectionLatitudeDegrees(double projectionLatitude) {
+        this.projectionLatitude = DTR * projectionLatitude;
+    }
+
+    public double getProjectionLatitudeDegrees() {
+        return projectionLatitude * RTD;
+    }
+
+    /**
+     * Set the projection longitude in radians.
+     */
+    public void setProjectionLongitude(double projectionLongitude) {
+        this.projectionLongitude = MapMath.normalizeLongitude(projectionLongitude);
+    }
+
+    public double getProjectionLongitude() {
+        return projectionLongitude;
+    }
+
+    /**
+     * Set the projection longitude in degrees.
+     */
+    public void setProjectionLongitudeDegrees(double projectionLongitude) {
+        this.projectionLongitude = DTR * projectionLongitude;
+    }
+
+    public double getProjectionLongitudeDegrees() {
+        return projectionLongitude * RTD;
+    }
+
+    /**
+     * Set the latitude of true scale in radians. This is only used by certain projections.
+     */
+    public void setTrueScaleLatitude(double trueScaleLatitude) {
+        this.trueScaleLatitude = trueScaleLatitude;
+    }
+
+    public double getTrueScaleLatitude() {
+        return trueScaleLatitude;
+    }
+
+    /**
+     * Set the latitude of true scale in degrees. This is only used by certain projections.
+     */
+    public void setTrueScaleLatitudeDegrees(double trueScaleLatitude) {
+        this.trueScaleLatitude = DTR * trueScaleLatitude;
+    }
+
+    public double getTrueScaleLatitudeDegrees() {
+        return trueScaleLatitude * RTD;
+    }
+
+    /**
+     * Set the false Northing in projected units.
+     */
+    public void setFalseNorthing(double falseNorthing) {
+        this.falseNorthing = falseNorthing;
+    }
+
+    public double getFalseNorthing() {
+        return falseNorthing;
+    }
+
+    /**
+     * Set the false Easting in projected units.
+     */
+    public void setFalseEasting(double falseEasting) {
+        this.falseEasting = falseEasting;
+    }
+
+    public double getFalseEasting() {
+        return falseEasting;
+    }
+
+    /**
+     * Set the projection scale factor. This is set to 1 by default.
+     */
+    public void setScaleFactor(double scaleFactor) {
+        this.scaleFactor = scaleFactor;
+    }
+
+    public double getScaleFactor() {
+        return scaleFactor;
+    }
+
+    public double getEquatorRadius() {
+        return a;
+    }
+
+    /**
+     * Set the conversion factor from metres to projected units. This is set to 1 by default.
+     */
+    public void setFromMetres(double fromMetres) {
+        this.fromMetres = fromMetres;
+    }
+
+    public double getFromMetres() {
+        return fromMetres;
+    }
+
+    public void setEllipsoid(Ellipsoid ellipsoid) {
+        this.ellipsoid = ellipsoid;
+        a = ellipsoid.equatorRadius;
+        e = ellipsoid.eccentricity;
+        es = ellipsoid.eccentricity2;
+    }
+
+    public Ellipsoid getEllipsoid() {
+        return ellipsoid;
+    }
+
+    /**
+     * Returns the ESPG code for this projection, or 0 if unknown.
+     */
+    public int getEPSGCode() {
+        return 0;
+    }
+
+    /**
+     * Initialize the projection. This should be called after setting parameters and before using the projection.
+     * This is for performance reasons as initialization may be expensive.
+     */
+    public void initialize() {
+        spherical = e == 0.0;
+        one_es = 1 - es;
+        rone_es = 1.0 / one_es;
+        totalScale = a * fromMetres;
+        totalFalseEasting = falseEasting * fromMetres;
+        totalFalseNorthing = falseNorthing * fromMetres;
+    }
+
+}
+
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ProjectionException.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ProjectionException.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ProjectionException.java	(revision 23351)
@@ -0,0 +1,27 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+   http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+*/
+
+package com.jhlabs.map.proj;
+
+public class ProjectionException extends RuntimeException {
+	public ProjectionException() {
+		super();
+	}
+
+	public ProjectionException(String message) {
+		super(message);
+	}
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ProjectionFactory.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ProjectionFactory.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/ProjectionFactory.java	(revision 23351)
@@ -0,0 +1,512 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+/**
+Bernhard Jenny, Institute of Cartography, ETH Zurich:
+Added private static Hashtable nameMap which maps between human-readable
+projection names and proj4 names.
+Changed ProjectionFactoryregister() to fill the new nameMap.
+Changed initialize() to instantiate nameMap.
+Added method getNamedProjection() to first map from a human-readable name to a
+proj4 name and then to a Projection class.
+Changed register(): the human-readable name of a projection is not passed anymore
+to register(), but the name is retreived from an instance of the projection. This
+avoids inconsistencies between names returned by the projection and names passed
+to register().
+ */
+package com.jhlabs.map.proj;
+
+import java.io.*;
+import java.util.*;
+import com.jhlabs.map.*;
+import java.awt.geom.Point2D;
+import java.util.logging.Level;
+import java.util.logging.Logger;
+
+public class ProjectionFactory {
+
+    private final static double SIXTH = .1666666666666666667; /* 1/6 */
+
+    private final static double RA4 = .04722222222222222222; /* 17/360 */
+
+    private final static double RA6 = .02215608465608465608; /* 67/3024 */
+
+    private final static double RV4 = .06944444444444444444; /* 5/72 */
+
+    private final static double RV6 = .04243827160493827160; /* 55/1296 */
+
+    private static AngleFormat format = new AngleFormat(AngleFormat.ddmmssPattern, true);
+
+    /**
+     * Return a projection initialized with a PROJ.4 argument list.
+     */
+    public static Projection fromPROJ4Specification(String[] args) {
+        Projection projection = null;
+        Ellipsoid ellipsoid = null;
+        double a = 0, b = 0, es = 0;
+
+        Hashtable params = new Hashtable();
+        for (int i = 0; i < args.length; i++) {
+            String arg = args[i];
+            if (arg.startsWith("+")) {
+                int index = arg.indexOf('=');
+                if (index != -1) {
+                    String key = arg.substring(1, index);
+                    String value = arg.substring(index + 1);
+                    params.put(key, value);
+                }
+            }
+        }
+
+        String s;
+        s = (String) params.get("proj");
+        if (s != null) {
+            projection = getNamedPROJ4Projection(s);
+            if (projection == null) {
+                throw new ProjectionException("Unknown projection: " + s);
+            }
+        }
+
+        s = (String) params.get("init");
+        if (s != null) {
+            projection = getNamedPROJ4CoordinateSystem(s);
+            if (projection == null) {
+                throw new ProjectionException("Unknown projection: " + s);
+            }
+            a = projection.getEquatorRadius();
+            es = projection.getEllipsoid().getEccentricitySquared();
+        }
+
+        // Set the ellipsoid
+        String ellipsoidName = "";
+        s = (String) params.get("R");
+        if (s != null) {
+            a = Double.parseDouble(s);
+        } else {
+            s = (String) params.get("ellps");
+            if (s == null) {
+                s = (String) params.get("datum");
+            }
+            if (s != null) {
+                Ellipsoid[] ellipsoids = Ellipsoid.ellipsoids;
+                for (int i = 0; i < ellipsoids.length; i++) {
+                    if (ellipsoids[i].shortName.equals(s)) {
+                        ellipsoid = ellipsoids[i];
+                        break;
+                    }
+                }
+                if (ellipsoid == null) {
+                    throw new ProjectionException("Unknown ellipsoid: " + s);
+                }
+                es = ellipsoid.eccentricity2;
+                a = ellipsoid.equatorRadius;
+                ellipsoidName = s;
+            } else {
+                s = (String) params.get("a");
+                if (s != null) {
+                    a = Double.parseDouble(s);
+                }
+                s = (String) params.get("es");
+                if (s != null) {
+                    es = Double.parseDouble(s);
+                } else {
+                    s = (String) params.get("rf");
+                    if (s != null) {
+                        es = Double.parseDouble(s);
+                        es = es * (2. - es);
+                    } else {
+                        s = (String) params.get("f");
+                        if (s != null) {
+                            es = Double.parseDouble(s);
+                            es = 1.0 / es;
+                            es = es * (2. - es);
+                        } else {
+                            s = (String) params.get("b");
+                            if (s != null) {
+                                b = Double.parseDouble(s);
+                                es = 1. - (b * b) / (a * a);
+                            }
+                        }
+                    }
+                }
+                if (b == 0) {
+                    b = a * Math.sqrt(1. - es);
+                }
+            }
+
+            s = (String) params.get("R_A");
+            if (s != null && Boolean.getBoolean(s)) {
+                a *= 1. - es * (SIXTH + es * (RA4 + es * RA6));
+            } else {
+                s = (String) params.get("R_V");
+                if (s != null && Boolean.getBoolean(s)) {
+                    a *= 1. - es * (SIXTH + es * (RV4 + es * RV6));
+                } else {
+                    s = (String) params.get("R_a");
+                    if (s != null && Boolean.getBoolean(s)) {
+                        a = .5 * (a + b);
+                    } else {
+                        s = (String) params.get("R_g");
+                        if (s != null && Boolean.getBoolean(s)) {
+                            a = Math.sqrt(a * b);
+                        } else {
+                            s = (String) params.get("R_h");
+                            if (s != null && Boolean.getBoolean(s)) {
+                                a = 2. * a * b / (a + b);
+                                es = 0.;
+                            } else {
+                                s = (String) params.get("R_lat_a");
+                                if (s != null) {
+                                    double tmp = Math.sin(parseAngle(s));
+                                    if (Math.abs(tmp) > MapMath.HALFPI) {
+                                        throw new ProjectionException("-11");
+                                    }
+                                    tmp = 1. - es * tmp * tmp;
+                                    a *= .5 * (1. - es + tmp) / (tmp * Math.sqrt(tmp));
+                                    es = 0.;
+                                } else {
+                                    s = (String) params.get("R_lat_g");
+                                    if (s != null) {
+                                        double tmp = Math.sin(parseAngle(s));
+                                        if (Math.abs(tmp) > MapMath.HALFPI) {
+                                            throw new ProjectionException("-11");
+                                        }
+                                        tmp = 1. - es * tmp * tmp;
+                                        a *= Math.sqrt(1. - es) / tmp;
+                                        es = 0.;
+                                    }
+                                }
+                            }
+                        }
+                    }
+                }
+            }
+        }
+        projection.setEllipsoid(new Ellipsoid(ellipsoidName, a, es, ellipsoidName));
+
+        // Other arguments
+//		projection.setProjectionLatitudeDegrees( 0 );
+//		projection.setProjectionLatitude1Degrees( 0 );
+//		projection.setProjectionLatitude2Degrees( 0 );
+        s = (String) params.get("lat_0");
+        if (s != null) {
+            projection.setProjectionLatitudeDegrees(parseAngle(s));
+        }
+        s = (String) params.get("lon_0");
+        if (s != null) {
+            projection.setProjectionLongitudeDegrees(parseAngle(s));
+        }
+        s = (String) params.get("lat_1");
+        if (s != null && projection instanceof ConicProjection) {
+            ConicProjection conic = (ConicProjection)projection;
+            conic.setProjectionLatitude1Degrees(parseAngle(s));
+        }
+        s = (String) params.get("lat_2");
+        if (s != null && projection instanceof ConicProjection) {
+            ConicProjection conic = (ConicProjection)projection;
+            conic.setProjectionLatitude2Degrees(parseAngle(s));
+        }
+        s = (String) params.get("lat_ts");
+        if (s != null) {
+            projection.setTrueScaleLatitudeDegrees(parseAngle(s));
+        }
+        s = (String) params.get("x_0");
+        if (s != null) {
+            projection.setFalseEasting(Double.parseDouble(s));
+        }
+        s = (String) params.get("y_0");
+        if (s != null) {
+            projection.setFalseNorthing(Double.parseDouble(s));
+        }
+
+        s = (String) params.get("k_0");
+        if (s == null) {
+            s = (String) params.get("k");
+        }
+        if (s != null) {
+            projection.setScaleFactor(Double.parseDouble(s));
+        }
+
+        s = (String) params.get("units");
+        if (s != null) {
+            Unit unit = Units.findUnits(s);
+            if (unit != null) {
+                projection.setFromMetres(1.0 / unit.value);
+            }
+        }
+        s = (String) params.get("to_meter");
+        if (s != null) {
+            projection.setFromMetres(1.0 / Double.parseDouble(s));
+        }
+
+        if (projection instanceof TransverseMercatorProjection) {
+            s = (String) params.get("zone");
+            if (s != null) {
+                ((TransverseMercatorProjection) projection).setUTMZone(Integer.parseInt(s));
+            }
+        }
+
+//zone
+//towgs84
+//alpha
+//datum
+//lat_ts
+//azi
+//lonc
+//rf
+//pm
+
+        projection.initialize();
+
+        return projection;
+    }
+
+    private static double parseAngle(String s) {
+        return format.parse(s, null).doubleValue();
+    }
+    private static Hashtable registry;
+    private static Hashtable nameMap;
+
+    private static void register(String proj4Name, Class cls) throws InstantiationException, IllegalAccessException {
+        try {
+            registry.put(proj4Name, cls);
+            Projection projection = (Projection) cls.newInstance();
+            String readableName = projection.getName();
+            nameMap.put(readableName, proj4Name);
+        } catch (InstantiationException e) {
+            System.err.println("unable to register " + proj4Name);
+            throw e;
+        }
+    }
+
+    public static Projection getNamedProjection(String name) {
+        if (registry == null) {
+            initialize();
+        }
+        String proj4Name = (String) nameMap.get(name);
+        return getNamedPROJ4Projection(proj4Name);
+    }
+
+    public static Projection getNamedPROJ4Projection(String name) {
+        if (registry == null) {
+            initialize();
+        }
+        Class cls = (Class) registry.get(name);
+        if (cls != null) {
+            try {
+                Projection projection = (Projection) cls.newInstance();
+                if (projection != null) {
+                    projection.setName(name); // is this needed ? FIXME
+                }
+                return projection;
+            } catch (IllegalAccessException e) {
+                e.printStackTrace();
+            } catch (InstantiationException e) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    public static Object[] getOrderedProjectionNames() {
+        if (registry == null) {
+            initialize();
+        }
+        Object[] names = nameMap.keySet().toArray();
+        Arrays.sort(names);
+        return names;
+    }
+
+    private static void initialize() {
+        try {
+            registry = new Hashtable();
+            nameMap = new Hashtable();
+            register("merc", MercatorProjection.class);
+        } catch (InstantiationException ex) {
+            Logger.getLogger(ProjectionFactory.class.getName()).log(Level.SEVERE, null, ex);
+        } catch (IllegalAccessException ex) {
+            Logger.getLogger(ProjectionFactory.class.getName()).log(Level.SEVERE, null, ex);
+        }
+    }
+
+    public static Projection readProjectionFile(String file, String name) throws IOException {
+        BufferedReader reader = new BufferedReader(new InputStreamReader(ProjectionFactory.class.getResourceAsStream("/nad/" + file)));
+        StreamTokenizer t = new StreamTokenizer(reader);
+        t.commentChar(
+                '#');
+        t.ordinaryChars(
+                '0', '9');
+        t.ordinaryChars(
+                '.', '.');
+        t.ordinaryChars(
+                '-', '-');
+        t.ordinaryChars(
+                '+', '+');
+        t.wordChars(
+                '0', '9');
+        t.wordChars(
+                '\'', '\'');
+        t.wordChars(
+                '"', '"');
+        t.wordChars(
+                '_', '_');
+        t.wordChars(
+                '.', '.');
+        t.wordChars(
+                '-', '-');
+        t.wordChars(
+                '+', '+');
+        t.wordChars(
+                ',', ',');
+        t.nextToken();
+
+        {
+            while (t.ttype == '<') {
+                t.nextToken();
+                if (t.ttype != StreamTokenizer.TT_WORD) {
+                    throw new IOException(t.lineno() + ": Word expected after '<'");
+                }
+            }
+            String cname = t.sval;
+            t.nextToken();
+            if (t.ttype != '>') {
+                throw new IOException(t.lineno() + ": '>' expected");
+            }
+            t.nextToken();
+            Vector v = new Vector();
+            String values = "";
+            while (t.ttype != '<') {
+                if (t.ttype == '+') {
+                    t.nextToken();
+                }
+                if (t.ttype != StreamTokenizer.TT_WORD) {
+                    throw new IOException(t.lineno() + ": Word expected after '+'");
+                }
+                String key = t.sval;
+                t.nextToken();
+                if (t.ttype == '=') {
+                    t.nextToken();
+                    //Removed check to allow for proj4 hack +nadgrids=@null
+                    //if ( t.ttype != StreamTokenizer.TT_WORD )
+                    //	throw new IOException( t.lineno()+": Value expected after '='" );
+                    String value = t.sval;
+                    t.nextToken();
+                    if (key.startsWith("+")) {
+                        v.add(key + "=" + value);
+                    } else {
+                        v.add("+" + key + "=" + value);
+                    }
+                }
+            }
+            t.nextToken();
+            if (t.ttype != '>') {
+                throw new IOException(t.lineno() + ": '<>' expected");
+            }
+            t.nextToken();
+            if (cname.equals(name)) {
+                String[] args = new String[v.size()];
+                v.copyInto(args);
+                reader.close();
+                return fromPROJ4Specification(args);
+            }
+        }
+
+        reader.close();
+        return null;
+    }
+
+    public static Projection getNamedPROJ4CoordinateSystem(String name) {
+        String[] files = {
+            "world",
+            "nad83",
+            "nad27",
+            "esri",
+            "epsg",};
+
+
+        try {
+            int p = name.indexOf(':');
+
+
+            if (p >= 0) {
+                return readProjectionFile(name.substring(0, p), name.substring(p + 1));
+            }
+
+
+            for (int i = 0; i
+                    < files.length; i++) {
+                Projection projection = readProjectionFile(files[i], name);
+
+
+                if (projection != null) {
+                    return projection;
+                }
+
+
+            }
+        } catch (IOException e) {
+            e.printStackTrace();
+
+
+        }
+        return null;
+
+
+    }
+
+    public static void main(String[] args) {
+        Projection projection = ProjectionFactory.fromPROJ4Specification(args);
+
+
+        if (projection != null) {
+            System.out.println(projection.getPROJ4Description());
+
+
+            for (int i = 0; i
+                    < args.length; i++) {
+                String arg = args[i];
+
+
+                if (!arg.startsWith("+") && !arg.startsWith("-")) {
+                    try {
+                        BufferedReader reader = new BufferedReader(new FileReader(new File(args[i])));
+                        Point2D.Double p = new Point2D.Double();
+                        String line;
+
+
+                        while ((line = reader.readLine()) != null) {
+                            StringTokenizer t = new StringTokenizer(line, " ");
+                            String slon = t.nextToken();
+                            String slat = t.nextToken();
+                            p.x = format.parse(slon, null).doubleValue();
+                            p.y = format.parse(slat, null).doubleValue();
+                            projection.transform(p, p);
+                            System.out.println(p.x + " " + p.y);
+
+
+                        }
+                    } catch (IOException e) {
+                        System.out.println("IOException: " + args[i] + ": " + e.getMessage());
+
+
+                    }
+                }
+            }
+        } else {
+            System.out.println("Can't find projection " + args[0]);
+        }
+
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/PseudoCylindricalProjection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/PseudoCylindricalProjection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/PseudoCylindricalProjection.java	(revision 23351)
@@ -0,0 +1,39 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+/**
+ * Bernhard Jenny, May 18 2010:
+ * Changed base class from CylindricalProjection to Projection, removed
+ * isRectilinear method, changed description of class.
+ * 23 September 2010: added parallelsAreParallel
+ */
+package com.jhlabs.map.proj;
+
+/**
+ * The superclass for all pseudo-cylindrical projections - eg. sinusoidal
+ * These are projections where parallels are straight and parallel, and
+ * meridians are curved.
+ */
+public abstract class PseudoCylindricalProjection extends Projection {
+
+    public String toString() {
+        return "Pseudo-Cylindrical";
+    }
+
+    public boolean parallelsAreParallel() {
+        return true;
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/TransverseMercatorProjection.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/TransverseMercatorProjection.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/com/jhlabs/map/proj/TransverseMercatorProjection.java	(revision 23351)
@@ -0,0 +1,221 @@
+/*
+Copyright 2006 Jerry Huxtable
+
+Licensed under the Apache License, Version 2.0 (the "License");
+you may not use this file except in compliance with the License.
+You may obtain a copy of the License at
+
+http://www.apache.org/licenses/LICENSE-2.0
+
+Unless required by applicable law or agreed to in writing, software
+distributed under the License is distributed on an "AS IS" BASIS,
+WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+See the License for the specific language governing permissions and
+limitations under the License.
+ */
+
+/*
+ * This file was semi-automatically converted from the public-domain USGS PROJ source.
+ */
+
+/**
+ * Corrected code for spherical case in projectInverse, added isConformal
+ * by Bernhard Jenny, February 2 2010.
+ */
+package com.jhlabs.map.proj;
+
+import com.jhlabs.map.Ellipsoid;
+import java.awt.geom.*;
+import com.jhlabs.map.*;
+
+/**
+ * Transverse Mercator Projection algorithm is taken from the USGS PROJ package.
+ */
+
+public class TransverseMercatorProjection extends CylindricalProjection {
+
+    private final static double FC1 = 1.0;
+    private final static double FC2 = 0.5;
+    private final static double FC3 = 0.16666666666666666666;
+    private final static double FC4 = 0.08333333333333333333;
+    private final static double FC5 = 0.05;
+    private final static double FC6 = 0.03333333333333333333;
+    private final static double FC7 = 0.02380952380952380952;
+    private final static double FC8 = 0.01785714285714285714;
+    private double esp;
+    private double ml0;
+    private double[] en;
+
+    public TransverseMercatorProjection() {
+        ellipsoid = Ellipsoid.GRS_1980;
+        projectionLatitude = Math.toRadians(0);
+        projectionLongitude = Math.toRadians(0);
+        minLongitude = Math.toRadians(-90);
+        maxLongitude = Math.toRadians(90);
+        initialize();
+    }
+
+    /**
+     * Set up a projection suitable for State Plane Coordinates.
+     */
+    public TransverseMercatorProjection(Ellipsoid ellipsoid, double lon_0, double lat_0, double k, double x_0, double y_0) {
+        setEllipsoid(ellipsoid);
+        projectionLongitude = lon_0;
+        projectionLatitude = lat_0;
+        scaleFactor = k;
+        falseEasting = x_0;
+        falseNorthing = y_0;
+        initialize();
+    }
+
+    public Object clone() {
+        TransverseMercatorProjection p = (TransverseMercatorProjection) super.clone();
+        if (en != null) {
+            p.en = (double[]) en.clone();
+        }
+        return p;
+    }
+
+    public boolean isRectilinear() {
+        return false;
+    }
+
+    public void initialize() {
+        super.initialize();
+        if (spherical) {
+            esp = scaleFactor;
+            ml0 = .5 * esp;
+        } else {
+            en = MapMath.enfn(es);
+            ml0 = MapMath.mlfn(projectionLatitude, Math.sin(projectionLatitude), Math.cos(projectionLatitude), en);
+            esp = es / (1. - es);
+        }
+    }
+
+    public int getRowFromNearestParallel(double latitude) {
+        int degrees = (int) MapMath.radToDeg(MapMath.normalizeLatitude(latitude));
+        if (degrees < -80 || degrees > 84) {
+            return 0;
+        }
+        if (degrees > 80) {
+            return 24;
+        }
+        return (degrees + 80) / 8 + 3;
+    }
+
+    public int getZoneFromNearestMeridian(double longitude) {
+        int zone = (int) Math.floor((MapMath.normalizeLongitude(longitude) + Math.PI) * 30.0 / Math.PI) + 1;
+        if (zone < 1) {
+            zone = 1;
+        } else if (zone > 60) {
+            zone = 60;
+        }
+        return zone;
+    }
+
+    public void setUTMZone(int zone) {
+        zone--;
+        projectionLongitude = (zone + .5) * Math.PI / 30. - Math.PI;
+        projectionLatitude = 0.0;
+        scaleFactor = 0.9996;
+        falseEasting = 500000;
+        initialize();
+    }
+
+    public Point2D.Double project(double lplam, double lpphi, Point2D.Double xy) {
+        if (spherical) {
+            double cosphi = Math.cos(lpphi);
+            double b = cosphi * Math.sin(lplam);
+
+            xy.x = ml0 * scaleFactor * Math.log((1. + b) / (1. - b));
+            double ty = cosphi * Math.cos(lplam) / Math.sqrt(1. - b * b);
+            ty = MapMath.acos(ty);
+            if (lpphi < 0.0) {
+                ty = -ty;
+            }
+            xy.y = esp * (ty - projectionLatitude);
+        } else {
+            double al, als, n, t;
+            double sinphi = Math.sin(lpphi);
+            double cosphi = Math.cos(lpphi);
+            t = Math.abs(cosphi) > 1e-10 ? sinphi / cosphi : 0.0;
+            t *= t;
+            al = cosphi * lplam;
+            als = al * al;
+            al /= Math.sqrt(1. - es * sinphi * sinphi);
+            n = esp * cosphi * cosphi;
+            xy.x = scaleFactor * al * (FC1
+                    + FC3 * als * (1. - t + n
+                    + FC5 * als * (5. + t * (t - 18.) + n * (14. - 58. * t)
+                    + FC7 * als * (61. + t * (t * (179. - t) - 479.)))));
+            xy.y = scaleFactor * (MapMath.mlfn(lpphi, sinphi, cosphi, en) - ml0
+                    + sinphi * al * lplam * FC2 * (1.
+                    + FC4 * als * (5. - t + n * (9. + 4. * n)
+                    + FC6 * als * (61. + t * (t - 58.) + n * (270. - 330 * t)
+                    + FC8 * als * (1385. + t * (t * (543. - t) - 3111.))))));
+        }
+        return xy;
+    }
+
+    public Point2D.Double projectInverse(double x, double y, Point2D.Double out) {
+        if (spherical) {
+            /*
+            Original code
+            x = Math.exp(x / scaleFactor);
+            y = .5 * (x - 1. / x);
+            x = Math.cos(projectionLatitude + y / scaleFactor);
+            out.y = MapMath.asin(Math.sqrt((1. - x * x) / (1. + y * y)));
+            if (y < 0) {
+            out.y = -out.y;
+            }
+            out.x = Math.atan2(y, x);
+             */
+
+            // new code by Bernhard Jenny, February 2 2010
+            double D = y / scaleFactor + projectionLatitude;
+            double xp = x / scaleFactor;
+
+            out.y = Math.asin(Math.sin(D) / Math.cosh(xp));
+            out.x = Math.atan2(Math.sinh(xp), Math.cos(D));
+        } else {
+            double n, con, cosphi, d, ds, sinphi, t;
+
+            out.y = MapMath.inv_mlfn(ml0 + y / scaleFactor, es, en);
+            if (Math.abs(y) >= MapMath.HALFPI) {
+                out.y = y < 0. ? -MapMath.HALFPI : MapMath.HALFPI;
+                out.x = 0.;
+            } else {
+                sinphi = Math.sin(out.y);
+                cosphi = Math.cos(out.y);
+                t = Math.abs(cosphi) > 1e-10 ? sinphi / cosphi : 0.;
+                n = esp * cosphi * cosphi;
+                d = x * Math.sqrt(con = 1. - es * sinphi * sinphi) / scaleFactor;
+                con *= t;
+                t *= t;
+                ds = d * d;
+                out.y -= (con * ds / (1. - es)) * FC2 * (1.
+                        - ds * FC4 * (5. + t * (3. - 9. * n) + n * (1. - 4 * n)
+                        - ds * FC6 * (61. + t * (90. - 252. * n
+                        + 45. * t) + 46. * n
+                        - ds * FC8 * (1385. + t * (3633. + t * (4095. + 1574. * t))))));
+                out.x = d * (FC1
+                        - ds * FC3 * (1. + 2. * t + n
+                        - ds * FC5 * (5. + t * (28. + 24. * t + 8. * n) + 6. * n
+                        - ds * FC7 * (61. + t * (662. + t * (1320. + 720. * t)))))) / cosphi;
+            }
+        }
+        return out;
+    }
+
+    public boolean hasInverse() {
+        return true;
+    }
+    
+    public boolean isConformal() {
+        return true;
+    }
+
+    public String toString() {
+        return "Transverse Mercator";
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISLayerFromFileAction.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISLayerFromFileAction.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISLayerFromFileAction.java	(revision 23351)
@@ -0,0 +1,60 @@
+package rgisopen;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import java.awt.event.ActionEvent;
+import java.io.File;
+import java.io.IOException;
+import javax.swing.JFileChooser;
+import javax.swing.JOptionPane;
+import javax.swing.filechooser.FileFilter;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+
+/**
+ * Action responsible for creation of a new layer based on
+ * an image file. Based on PicLayer's NewLayerFromFileAction.
+ */
+public class RGISLayerFromFileAction extends JosmAction {
+    /**
+     * Provides filtering of only image files.
+     */
+    private class ImageFileFilter extends FileFilter {
+        @Override
+        public boolean accept( File f ) {
+            return f.isDirectory() || f.getName().endsWith(".png");
+        }
+
+        @Override
+        public String getDescription() {
+            return tr("Image files");
+        }
+    }
+
+    public RGISLayerFromFileAction() {
+        super(tr("New picture layer from RGIS..."), null, null, null, false);
+    }
+
+    public void actionPerformed( ActionEvent arg0 ) {
+        // Choose a file
+        JFileChooser fc = new JFileChooser();
+        fc.setAcceptAllFileFilterUsed(false);
+        fc.setFileFilter(new ImageFileFilter());
+        int result = fc.showOpenDialog(Main.parent);
+
+        // Create a layer?
+        if( result == JFileChooser.APPROVE_OPTION ) {
+            // Create layer from file
+            RGISPicLayer layer = new RGISPicLayer(fc.getSelectedFile());
+            // Add layer only if successfully initialized
+            try {
+                layer.initialize();
+                Main.main.addLayer(layer);
+            } catch( IOException e ) {
+                // Failed
+                System.out.println("RGISLayerFromFileAction::actionPerformed - " + e.getMessage());
+                JOptionPane.showMessageDialog(null, e.getMessage());
+                return;
+            }
+        }
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISOpenPlugin.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISOpenPlugin.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISOpenPlugin.java	(revision 23351)
@@ -0,0 +1,56 @@
+package rgisopen;
+
+import static org.openstreetmap.josm.tools.I18n.marktr;
+
+import java.awt.event.KeyEvent;
+import javax.swing.JMenu;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.MapView.LayerChangeListener;
+import org.openstreetmap.josm.gui.layer.Layer;
+
+/**
+ * Main Plugin class.
+ */
+public class RGISOpenPlugin extends Plugin implements LayerChangeListener {
+    private JMenu menu = null;
+    private RGISLayerFromFileAction rgisAction = null;
+
+    public RGISOpenPlugin( PluginInformation info ) {
+        super(info);
+
+        if( Main.main.menu != null ) {
+            for( int i = 0; i < Main.main.menu.getMenuCount(); i++ ) {
+                JMenu m = Main.main.menu.getMenu(i);
+                if( m.getName() != null && m.getName().equals(marktr("PicLayer")) ) {
+                    menu = m;
+                }
+            }
+            if( menu == null ) {
+                menu = Main.main.menu.addMenu(marktr("RGIS"), KeyEvent.VK_I, Main.main.menu.defaultMenuPos, null);
+            }
+        }
+
+        if( menu != null ) {
+            rgisAction = new RGISLayerFromFileAction();
+            menu.add(rgisAction);
+            rgisAction.setEnabled(false);
+        }
+
+        MapView.addLayerChangeListener(this);
+    }
+
+    public void activeLayerChange( Layer oldLayer, Layer newLayer ) {
+    }
+
+    public void layerAdded( Layer arg0 ) {
+        rgisAction.setEnabled(true);
+    }
+
+    public void layerRemoved( Layer arg0 ) {
+        rgisAction.setEnabled(!Main.map.mapView.getAllLayers().isEmpty());
+    }
+};
Index: applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISPicLayer.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISPicLayer.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISPicLayer.java	(revision 23351)
@@ -0,0 +1,37 @@
+package rgisopen;
+
+import java.awt.Image;
+import java.io.File;
+import java.io.IOException;
+import javax.imageio.ImageIO;
+import org.openstreetmap.josm.plugins.piclayer.PicLayerAbstract;
+
+/**
+ * Modified PicLayerFromFile, ok.
+ */
+public class RGISPicLayer extends PicLayerAbstract {
+    // File to load from.
+    private File m_file;
+    // Tooltip text
+    private String m_tooltiptext;
+
+    public RGISPicLayer( File file ) {
+        // Remember the file
+        m_file = file;
+        // Generate tooltip text
+        m_tooltiptext = m_file.getAbsolutePath();
+    }
+
+    @Override
+    protected Image createImage() throws IOException {
+        // Try to load file
+        Image image = null;
+        image = ImageIO.read(m_file);
+        return image;
+    }
+
+    @Override
+    protected String getPicLayerName() {
+        return m_tooltiptext;
+    }
+}
Index: applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISimageLayer.java
===================================================================
--- applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISimageLayer.java	(revision 23351)
+++ applications/editors/josm/plugins/rgisopen/src/rgisopen/RGISimageLayer.java	(revision 23351)
@@ -0,0 +1,197 @@
+package rgisopen;
+
+import com.jhlabs.map.proj.Projection;
+import com.jhlabs.map.proj.ProjectionFactory;
+import java.awt.Graphics2D;
+import java.awt.geom.Point2D;
+import java.awt.image.BufferedImage;
+import java.io.File;
+import java.net.MalformedURLException;
+import java.util.HashMap;
+import java.util.Map;
+import javax.imageio.ImageIO;
+import javax.swing.Action;
+import javax.swing.Icon;
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
+import org.openstreetmap.josm.gui.MapView;
+import org.openstreetmap.josm.gui.layer.Layer;
+
+/**
+ * Image Layer (based on PicLayer source code) that displays RGIS data.
+ * Geolocated with url parameters, but adjustable.
+ *
+ * @author Zverik
+ */
+public class RGISimageLayer extends Layer {
+
+    private static int counter = 0;
+    private BufferedImage image = null;
+    private EastNorth position;
+    private double scale = 1.0;
+    private String tooltipText = "";
+    private Icon layerIcon = null;
+
+    // init parameters
+    private File imageFile = null;
+    private String url;
+
+    // parsed url parameters
+    private double iscale;
+    private LatLon ipos;
+
+    public RGISimageLayer( File file, String url ) {
+        super("RGIS Image" + (++counter > 1 ? " " + counter : ""));
+        imageFile = file;
+        this.url = url;
+        tooltipText = file.getAbsolutePath();
+    }
+
+    public void init() throws Exception {
+        try {
+            image = ImageIO.read(imageFile);
+        } catch( Exception e ) {
+            image = null;
+            System.err.println("Cannot load image " + imageFile.getAbsolutePath() + ": " + e.getMessage());
+        }
+
+        Map<String, Double> params = parseUrl(url);
+        int width = params.get("width").intValue();
+        int height = params.get("height").intValue();
+        double x = params.get("x");
+        double y = params.get("y");
+        double zoom = params.get("zoom");
+
+        if( width != image.getWidth() || height != image.getHeight() )
+            throw new IllegalArgumentException("Image size is different from URL parameters");
+        if( x < 50000 || x > 150000 || y < 50000 || y > 150000 )
+            throw new IllegalArgumentException("URL coordinates are out of bounds");
+        double scale = zoom / width * 3779.527559;
+        if( scale < 500 || scale > 1000000 )
+            throw new IllegalArgumentException("Scale in URL is out of bounds");
+        iscale = scale;
+        ipos = convertCoords(x, y);
+        position = Main.proj.latlon2eastNorth(ipos);
+    }
+
+    private LatLon convertCoords( double x, double y ) {
+        Projection proj = ProjectionFactory.fromPROJ4Specification(new String[] {
+            "+proj=merc",
+            "+lat_0=0",
+            "+lon_0=30",
+            "+k=1",
+            "+x_0=95936",
+            "+y_0=-6552814",
+            "+ellps=krass",
+            "+units=m",
+            "+towgs84=23.57,-141.00,-79.85,0.000,-0.350,-0.790,0.00",
+            "+no_defs"
+        });
+        Point2D.Double coord = proj.inverseTransform(new Point2D.Double(x, y), new Point2D.Double());
+        return new LatLon(coord.x, coord.y);
+    }
+
+    /**
+     * parses query parameters into a map.
+     */
+    private static Map<String, Double> parseUrl( String url ) throws MalformedURLException {
+        Map<String, Double> result = new HashMap<String, Double>();
+        int state = 0; // 0=search for ?, 1=key, 2=value
+        char[] urlc = (url+"&").toCharArray();
+        StringBuilder key = new StringBuilder();
+        StringBuilder value = new StringBuilder();
+        for( char ch : urlc ) {
+            if( state == 0 && (ch == '?' || ch == '&') ) {
+                state = 1;
+                key.setLength(0);
+            } else if( state == 1 ) {
+                if( ch == '=' ) {
+                    state = 2;
+                    value.setLength(0);
+                } else if( ch == '&' ) {
+                    // empty key - of no use
+                    key = new StringBuilder();
+                } else {
+                    key.append(Character.toLowerCase(ch));
+                }
+            } else if( state == 2 ) {
+                if( ch == '&' ) {
+                    // found key/value
+                    try {
+                        result.put(key.toString(), Double.parseDouble(value.toString()));
+                    } catch( NumberFormatException e ) {}
+                } else if( Character.isDigit(ch) || ch == '.' ) {
+                    value.append(ch);
+                } else {
+                    // unknown character - skip this key
+                    state = 0;
+                }
+            }
+        }
+        return result;
+    }
+
+    @Override
+    public void paint(Graphics2D g2, MapView mv, Bounds box) {
+        if( image != null ) {
+            // Position image at the right graphical place
+            EastNorth center = Main.map.mapView.getCenter();
+            EastNorth leftop = Main.map.mapView.getEastNorth( 0, 0 );
+            double pixel_per_en = ( Main.map.mapView.getWidth() / 2.0 ) / ( center.east() - leftop.east() );
+
+            //     This is now the offset in screen pixels
+            double pic_offset_x = (( position.east() - leftop.east() ) * pixel_per_en);
+            double pic_offset_y = (( leftop.north() - position.north() ) * pixel_per_en);
+
+            // Let's use Graphics 2D
+            Graphics2D g = (Graphics2D)g2.create();
+            // Move
+            g.translate( pic_offset_x, pic_offset_y );
+            // Scale
+            double scalex = scale / Main.map.mapView.getDist100Pixel();
+//            g.scale( scalex, scalex );
+
+            // Draw picture
+            g.drawImage( image, -image.getWidth() / 2, -image.getHeight() / 2, null );
+        } else {
+            System.err.println("RGISImagelayer: where is image?");
+        }
+    }
+
+    @Override
+    public Icon getIcon() {
+        return layerIcon;
+    }
+
+    @Override
+    public String getToolTipText() {
+        return tooltipText;
+    }
+
+    @Override
+    public void mergeFrom(Layer from) {
+    }
+
+    @Override
+    public boolean isMergable(Layer other) {
+        return false;
+    }
+
+    @Override
+    public void visitBoundingBox(BoundingXYVisitor v) {
+    }
+
+    @Override
+    public Object getInfoComponent() {
+        return null;
+    }
+
+    @Override
+    public Action[] getMenuEntries() {
+        return new Action[] {};
+    }
+
+}
