Index: /applications/editors/josm/plugins/epsg31287/.classpath
===================================================================
--- /applications/editors/josm/plugins/epsg31287/.classpath	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/.classpath	(revision 23660)
@@ -0,0 +1,7 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<classpath>
+	<classpathentry kind="src" path="src"/>
+	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-1.6"/>
+	<classpathentry kind="lib" path="/JOSM/build"/>
+	<classpathentry kind="output" path="bin"/>
+</classpath>
Index: /applications/editors/josm/plugins/epsg31287/.project
===================================================================
--- /applications/editors/josm/plugins/epsg31287/.project	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/.project	(revision 23660)
@@ -0,0 +1,17 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<projectDescription>
+	<name>EPSG31287</name>
+	<comment></comment>
+	<projects>
+	</projects>
+	<buildSpec>
+		<buildCommand>
+			<name>org.eclipse.jdt.core.javabuilder</name>
+			<arguments>
+			</arguments>
+		</buildCommand>
+	</buildSpec>
+	<natures>
+		<nature>org.eclipse.jdt.core.javanature</nature>
+	</natures>
+</projectDescription>
Index: /applications/editors/josm/plugins/epsg31287/.settings/org.eclipse.jdt.core.prefs
===================================================================
--- /applications/editors/josm/plugins/epsg31287/.settings/org.eclipse.jdt.core.prefs	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/.settings/org.eclipse.jdt.core.prefs	(revision 23660)
@@ -0,0 +1,12 @@
+#Tue Oct 12 21:04:10 CEST 2010
+eclipse.preferences.version=1
+org.eclipse.jdt.core.compiler.codegen.inlineJsrBytecode=enabled
+org.eclipse.jdt.core.compiler.codegen.targetPlatform=1.6
+org.eclipse.jdt.core.compiler.codegen.unusedLocal=preserve
+org.eclipse.jdt.core.compiler.compliance=1.6
+org.eclipse.jdt.core.compiler.debug.lineNumber=generate
+org.eclipse.jdt.core.compiler.debug.localVariable=generate
+org.eclipse.jdt.core.compiler.debug.sourceFile=generate
+org.eclipse.jdt.core.compiler.problem.assertIdentifier=error
+org.eclipse.jdt.core.compiler.problem.enumIdentifier=error
+org.eclipse.jdt.core.compiler.source=1.6
Index: /applications/editors/josm/plugins/epsg31287/GPL-v3.0.txt
===================================================================
--- /applications/editors/josm/plugins/epsg31287/GPL-v3.0.txt	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/GPL-v3.0.txt	(revision 23660)
@@ -0,0 +1,674 @@
+                    GNU GENERAL PUBLIC LICENSE
+                       Version 3, 29 June 2007
+
+ Copyright (C) 2007 Free Software Foundation, Inc. <http://fsf.org/>
+ Everyone is permitted to copy and distribute verbatim copies
+ of this license document, but changing it is not allowed.
+
+                            Preamble
+
+  The GNU General Public License is a free, copyleft license for
+software and other kinds of works.
+
+  The licenses for most software and other practical works are designed
+to take away your freedom to share and change the works.  By contrast,
+the GNU General Public License is intended to guarantee your freedom to
+share and change all versions of a program--to make sure it remains free
+software for all its users.  We, the Free Software Foundation, use the
+GNU General Public License for most of our software; it applies also to
+any other work released this way by its authors.  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
+them 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 prevent others from denying you
+these rights or asking you to surrender the rights.  Therefore, you have
+certain responsibilities if you distribute copies of the software, or if
+you modify it: responsibilities to respect the freedom of others.
+
+  For example, if you distribute copies of such a program, whether
+gratis or for a fee, you must pass on to the recipients the same
+freedoms that you received.  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.
+
+  Developers that use the GNU GPL protect your rights with two steps:
+(1) assert copyright on the software, and (2) offer you this License
+giving you legal permission to copy, distribute and/or modify it.
+
+  For the developers' and authors' protection, the GPL clearly explains
+that there is no warranty for this free software.  For both users' and
+authors' sake, the GPL requires that modified versions be marked as
+changed, so that their problems will not be attributed erroneously to
+authors of previous versions.
+
+  Some devices are designed to deny users access to install or run
+modified versions of the software inside them, although the manufacturer
+can do so.  This is fundamentally incompatible with the aim of
+protecting users' freedom to change the software.  The systematic
+pattern of such abuse occurs in the area of products for individuals to
+use, which is precisely where it is most unacceptable.  Therefore, we
+have designed this version of the GPL to prohibit the practice for those
+products.  If such problems arise substantially in other domains, we
+stand ready to extend this provision to those domains in future versions
+of the GPL, as needed to protect the freedom of users.
+
+  Finally, every program is threatened constantly by software patents.
+States should not allow patents to restrict development and use of
+software on general-purpose computers, but in those that do, we wish to
+avoid the special danger that patents applied to a free program could
+make it effectively proprietary.  To prevent this, the GPL assures that
+patents cannot be used to render the program non-free.
+
+  The precise terms and conditions for copying, distribution and
+modification follow.
+
+                       TERMS AND CONDITIONS
+
+  0. Definitions.
+
+  "This License" refers to version 3 of the GNU General Public License.
+
+  "Copyright" also means copyright-like laws that apply to other kinds of
+works, such as semiconductor masks.
+
+  "The Program" refers to any copyrightable work licensed under this
+License.  Each licensee is addressed as "you".  "Licensees" and
+"recipients" may be individuals or organizations.
+
+  To "modify" a work means to copy from or adapt all or part of the work
+in a fashion requiring copyright permission, other than the making of an
+exact copy.  The resulting work is called a "modified version" of the
+earlier work or a work "based on" the earlier work.
+
+  A "covered work" means either the unmodified Program or a work based
+on the Program.
+
+  To "propagate" a work means to do anything with it that, without
+permission, would make you directly or secondarily liable for
+infringement under applicable copyright law, except executing it on a
+computer or modifying a private copy.  Propagation includes copying,
+distribution (with or without modification), making available to the
+public, and in some countries other activities as well.
+
+  To "convey" a work means any kind of propagation that enables other
+parties to make or receive copies.  Mere interaction with a user through
+a computer network, with no transfer of a copy, is not conveying.
+
+  An interactive user interface displays "Appropriate Legal Notices"
+to the extent that it includes a convenient and prominently visible
+feature that (1) displays an appropriate copyright notice, and (2)
+tells the user that there is no warranty for the work (except to the
+extent that warranties are provided), that licensees may convey the
+work under this License, and how to view a copy of this License.  If
+the interface presents a list of user commands or options, such as a
+menu, a prominent item in the list meets this criterion.
+
+  1. Source Code.
+
+  The "source code" for a work means the preferred form of the work
+for making modifications to it.  "Object code" means any non-source
+form of a work.
+
+  A "Standard Interface" means an interface that either is an official
+standard defined by a recognized standards body, or, in the case of
+interfaces specified for a particular programming language, one that
+is widely used among developers working in that language.
+
+  The "System Libraries" of an executable work include anything, other
+than the work as a whole, that (a) is included in the normal form of
+packaging a Major Component, but which is not part of that Major
+Component, and (b) serves only to enable use of the work with that
+Major Component, or to implement a Standard Interface for which an
+implementation is available to the public in source code form.  A
+"Major Component", in this context, means a major essential component
+(kernel, window system, and so on) of the specific operating system
+(if any) on which the executable work runs, or a compiler used to
+produce the work, or an object code interpreter used to run it.
+
+  The "Corresponding Source" for a work in object code form means all
+the source code needed to generate, install, and (for an executable
+work) run the object code and to modify the work, including scripts to
+control those activities.  However, it does not include the work's
+System Libraries, or general-purpose tools or generally available free
+programs which are used unmodified in performing those activities but
+which are not part of the work.  For example, Corresponding Source
+includes interface definition files associated with source files for
+the work, and the source code for shared libraries and dynamically
+linked subprograms that the work is specifically designed to require,
+such as by intimate data communication or control flow between those
+subprograms and other parts of the work.
+
+  The Corresponding Source need not include anything that users
+can regenerate automatically from other parts of the Corresponding
+Source.
+
+  The Corresponding Source for a work in source code form is that
+same work.
+
+  2. Basic Permissions.
+
+  All rights granted under this License are granted for the term of
+copyright on the Program, and are irrevocable provided the stated
+conditions are met.  This License explicitly affirms your unlimited
+permission to run the unmodified Program.  The output from running a
+covered work is covered by this License only if the output, given its
+content, constitutes a covered work.  This License acknowledges your
+rights of fair use or other equivalent, as provided by copyright law.
+
+  You may make, run and propagate covered works that you do not
+convey, without conditions so long as your license otherwise remains
+in force.  You may convey covered works to others for the sole purpose
+of having them make modifications exclusively for you, or provide you
+with facilities for running those works, provided that you comply with
+the terms of this License in conveying all material for which you do
+not control copyright.  Those thus making or running the covered works
+for you must do so exclusively on your behalf, under your direction
+and control, on terms that prohibit them from making any copies of
+your copyrighted material outside their relationship with you.
+
+  Conveying under any other circumstances is permitted solely under
+the conditions stated below.  Sublicensing is not allowed; section 10
+makes it unnecessary.
+
+  3. Protecting Users' Legal Rights From Anti-Circumvention Law.
+
+  No covered work shall be deemed part of an effective technological
+measure under any applicable law fulfilling obligations under article
+11 of the WIPO copyright treaty adopted on 20 December 1996, or
+similar laws prohibiting or restricting circumvention of such
+measures.
+
+  When you convey a covered work, you waive any legal power to forbid
+circumvention of technological measures to the extent such circumvention
+is effected by exercising rights under this License with respect to
+the covered work, and you disclaim any intention to limit operation or
+modification of the work as a means of enforcing, against the work's
+users, your or third parties' legal rights to forbid circumvention of
+technological measures.
+
+  4. Conveying Verbatim Copies.
+
+  You may convey 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;
+keep intact all notices stating that this License and any
+non-permissive terms added in accord with section 7 apply to the code;
+keep intact all notices of the absence of any warranty; and give all
+recipients a copy of this License along with the Program.
+
+  You may charge any price or no price for each copy that you convey,
+and you may offer support or warranty protection for a fee.
+
+  5. Conveying Modified Source Versions.
+
+  You may convey a work based on the Program, or the modifications to
+produce it from the Program, in the form of source code under the
+terms of section 4, provided that you also meet all of these conditions:
+
+    a) The work must carry prominent notices stating that you modified
+    it, and giving a relevant date.
+
+    b) The work must carry prominent notices stating that it is
+    released under this License and any conditions added under section
+    7.  This requirement modifies the requirement in section 4 to
+    "keep intact all notices".
+
+    c) You must license the entire work, as a whole, under this
+    License to anyone who comes into possession of a copy.  This
+    License will therefore apply, along with any applicable section 7
+    additional terms, to the whole of the work, and all its parts,
+    regardless of how they are packaged.  This License gives no
+    permission to license the work in any other way, but it does not
+    invalidate such permission if you have separately received it.
+
+    d) If the work has interactive user interfaces, each must display
+    Appropriate Legal Notices; however, if the Program has interactive
+    interfaces that do not display Appropriate Legal Notices, your
+    work need not make them do so.
+
+  A compilation of a covered work with other separate and independent
+works, which are not by their nature extensions of the covered work,
+and which are not combined with it such as to form a larger program,
+in or on a volume of a storage or distribution medium, is called an
+"aggregate" if the compilation and its resulting copyright are not
+used to limit the access or legal rights of the compilation's users
+beyond what the individual works permit.  Inclusion of a covered work
+in an aggregate does not cause this License to apply to the other
+parts of the aggregate.
+
+  6. Conveying Non-Source Forms.
+
+  You may convey a covered work in object code form under the terms
+of sections 4 and 5, provided that you also convey the
+machine-readable Corresponding Source under the terms of this License,
+in one of these ways:
+
+    a) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by the
+    Corresponding Source fixed on a durable physical medium
+    customarily used for software interchange.
+
+    b) Convey the object code in, or embodied in, a physical product
+    (including a physical distribution medium), accompanied by a
+    written offer, valid for at least three years and valid for as
+    long as you offer spare parts or customer support for that product
+    model, to give anyone who possesses the object code either (1) a
+    copy of the Corresponding Source for all the software in the
+    product that is covered by this License, on a durable physical
+    medium customarily used for software interchange, for a price no
+    more than your reasonable cost of physically performing this
+    conveying of source, or (2) access to copy the
+    Corresponding Source from a network server at no charge.
+
+    c) Convey individual copies of the object code with a copy of the
+    written offer to provide the Corresponding Source.  This
+    alternative is allowed only occasionally and noncommercially, and
+    only if you received the object code with such an offer, in accord
+    with subsection 6b.
+
+    d) Convey the object code by offering access from a designated
+    place (gratis or for a charge), and offer equivalent access to the
+    Corresponding Source in the same way through the same place at no
+    further charge.  You need not require recipients to copy the
+    Corresponding Source along with the object code.  If the place to
+    copy the object code is a network server, the Corresponding Source
+    may be on a different server (operated by you or a third party)
+    that supports equivalent copying facilities, provided you maintain
+    clear directions next to the object code saying where to find the
+    Corresponding Source.  Regardless of what server hosts the
+    Corresponding Source, you remain obligated to ensure that it is
+    available for as long as needed to satisfy these requirements.
+
+    e) Convey the object code using peer-to-peer transmission, provided
+    you inform other peers where the object code and Corresponding
+    Source of the work are being offered to the general public at no
+    charge under subsection 6d.
+
+  A separable portion of the object code, whose source code is excluded
+from the Corresponding Source as a System Library, need not be
+included in conveying the object code work.
+
+  A "User Product" is either (1) a "consumer product", which means any
+tangible personal property which is normally used for personal, family,
+or household purposes, or (2) anything designed or sold for incorporation
+into a dwelling.  In determining whether a product is a consumer product,
+doubtful cases shall be resolved in favor of coverage.  For a particular
+product received by a particular user, "normally used" refers to a
+typical or common use of that class of product, regardless of the status
+of the particular user or of the way in which the particular user
+actually uses, or expects or is expected to use, the product.  A product
+is a consumer product regardless of whether the product has substantial
+commercial, industrial or non-consumer uses, unless such uses represent
+the only significant mode of use of the product.
+
+  "Installation Information" for a User Product means any methods,
+procedures, authorization keys, or other information required to install
+and execute modified versions of a covered work in that User Product from
+a modified version of its Corresponding Source.  The information must
+suffice to ensure that the continued functioning of the modified object
+code is in no case prevented or interfered with solely because
+modification has been made.
+
+  If you convey an object code work under this section in, or with, or
+specifically for use in, a User Product, and the conveying occurs as
+part of a transaction in which the right of possession and use of the
+User Product is transferred to the recipient in perpetuity or for a
+fixed term (regardless of how the transaction is characterized), the
+Corresponding Source conveyed under this section must be accompanied
+by the Installation Information.  But this requirement does not apply
+if neither you nor any third party retains the ability to install
+modified object code on the User Product (for example, the work has
+been installed in ROM).
+
+  The requirement to provide Installation Information does not include a
+requirement to continue to provide support service, warranty, or updates
+for a work that has been modified or installed by the recipient, or for
+the User Product in which it has been modified or installed.  Access to a
+network may be denied when the modification itself materially and
+adversely affects the operation of the network or violates the rules and
+protocols for communication across the network.
+
+  Corresponding Source conveyed, and Installation Information provided,
+in accord with this section must be in a format that is publicly
+documented (and with an implementation available to the public in
+source code form), and must require no special password or key for
+unpacking, reading or copying.
+
+  7. Additional Terms.
+
+  "Additional permissions" are terms that supplement the terms of this
+License by making exceptions from one or more of its conditions.
+Additional permissions that are applicable to the entire Program shall
+be treated as though they were included in this License, to the extent
+that they are valid under applicable law.  If additional permissions
+apply only to part of the Program, that part may be used separately
+under those permissions, but the entire Program remains governed by
+this License without regard to the additional permissions.
+
+  When you convey a copy of a covered work, you may at your option
+remove any additional permissions from that copy, or from any part of
+it.  (Additional permissions may be written to require their own
+removal in certain cases when you modify the work.)  You may place
+additional permissions on material, added by you to a covered work,
+for which you have or can give appropriate copyright permission.
+
+  Notwithstanding any other provision of this License, for material you
+add to a covered work, you may (if authorized by the copyright holders of
+that material) supplement the terms of this License with terms:
+
+    a) Disclaiming warranty or limiting liability differently from the
+    terms of sections 15 and 16 of this License; or
+
+    b) Requiring preservation of specified reasonable legal notices or
+    author attributions in that material or in the Appropriate Legal
+    Notices displayed by works containing it; or
+
+    c) Prohibiting misrepresentation of the origin of that material, or
+    requiring that modified versions of such material be marked in
+    reasonable ways as different from the original version; or
+
+    d) Limiting the use for publicity purposes of names of licensors or
+    authors of the material; or
+
+    e) Declining to grant rights under trademark law for use of some
+    trade names, trademarks, or service marks; or
+
+    f) Requiring indemnification of licensors and authors of that
+    material by anyone who conveys the material (or modified versions of
+    it) with contractual assumptions of liability to the recipient, for
+    any liability that these contractual assumptions directly impose on
+    those licensors and authors.
+
+  All other non-permissive additional terms are considered "further
+restrictions" within the meaning of section 10.  If the Program as you
+received it, or any part of it, contains a notice stating that it is
+governed by this License along with a term that is a further
+restriction, you may remove that term.  If a license document contains
+a further restriction but permits relicensing or conveying under this
+License, you may add to a covered work material governed by the terms
+of that license document, provided that the further restriction does
+not survive such relicensing or conveying.
+
+  If you add terms to a covered work in accord with this section, you
+must place, in the relevant source files, a statement of the
+additional terms that apply to those files, or a notice indicating
+where to find the applicable terms.
+
+  Additional terms, permissive or non-permissive, may be stated in the
+form of a separately written license, or stated as exceptions;
+the above requirements apply either way.
+
+  8. Termination.
+
+  You may not propagate or modify a covered work except as expressly
+provided under this License.  Any attempt otherwise to propagate or
+modify it is void, and will automatically terminate your rights under
+this License (including any patent licenses granted under the third
+paragraph of section 11).
+
+  However, if you cease all violation of this License, then your
+license from a particular copyright holder is reinstated (a)
+provisionally, unless and until the copyright holder explicitly and
+finally terminates your license, and (b) permanently, if the copyright
+holder fails to notify you of the violation by some reasonable means
+prior to 60 days after the cessation.
+
+  Moreover, your license from a particular copyright holder is
+reinstated permanently if the copyright holder notifies you of the
+violation by some reasonable means, this is the first time you have
+received notice of violation of this License (for any work) from that
+copyright holder, and you cure the violation prior to 30 days after
+your receipt of the notice.
+
+  Termination of your rights under this section does not terminate the
+licenses of parties who have received copies or rights from you under
+this License.  If your rights have been terminated and not permanently
+reinstated, you do not qualify to receive new licenses for the same
+material under section 10.
+
+  9. Acceptance Not Required for Having Copies.
+
+  You are not required to accept this License in order to receive or
+run a copy of the Program.  Ancillary propagation of a covered work
+occurring solely as a consequence of using peer-to-peer transmission
+to receive a copy likewise does not require acceptance.  However,
+nothing other than this License grants you permission to propagate or
+modify any covered work.  These actions infringe copyright if you do
+not accept this License.  Therefore, by modifying or propagating a
+covered work, you indicate your acceptance of this License to do so.
+
+  10. Automatic Licensing of Downstream Recipients.
+
+  Each time you convey a covered work, the recipient automatically
+receives a license from the original licensors, to run, modify and
+propagate that work, subject to this License.  You are not responsible
+for enforcing compliance by third parties with this License.
+
+  An "entity transaction" is a transaction transferring control of an
+organization, or substantially all assets of one, or subdividing an
+organization, or merging organizations.  If propagation of a covered
+work results from an entity transaction, each party to that
+transaction who receives a copy of the work also receives whatever
+licenses to the work the party's predecessor in interest had or could
+give under the previous paragraph, plus a right to possession of the
+Corresponding Source of the work from the predecessor in interest, if
+the predecessor has it or can get it with reasonable efforts.
+
+  You may not impose any further restrictions on the exercise of the
+rights granted or affirmed under this License.  For example, you may
+not impose a license fee, royalty, or other charge for exercise of
+rights granted under this License, and you may not initiate litigation
+(including a cross-claim or counterclaim in a lawsuit) alleging that
+any patent claim is infringed by making, using, selling, offering for
+sale, or importing the Program or any portion of it.
+
+  11. Patents.
+
+  A "contributor" is a copyright holder who authorizes use under this
+License of the Program or a work on which the Program is based.  The
+work thus licensed is called the contributor's "contributor version".
+
+  A contributor's "essential patent claims" are all patent claims
+owned or controlled by the contributor, whether already acquired or
+hereafter acquired, that would be infringed by some manner, permitted
+by this License, of making, using, or selling its contributor version,
+but do not include claims that would be infringed only as a
+consequence of further modification of the contributor version.  For
+purposes of this definition, "control" includes the right to grant
+patent sublicenses in a manner consistent with the requirements of
+this License.
+
+  Each contributor grants you a non-exclusive, worldwide, royalty-free
+patent license under the contributor's essential patent claims, to
+make, use, sell, offer for sale, import and otherwise run, modify and
+propagate the contents of its contributor version.
+
+  In the following three paragraphs, a "patent license" is any express
+agreement or commitment, however denominated, not to enforce a patent
+(such as an express permission to practice a patent or covenant not to
+sue for patent infringement).  To "grant" such a patent license to a
+party means to make such an agreement or commitment not to enforce a
+patent against the party.
+
+  If you convey a covered work, knowingly relying on a patent license,
+and the Corresponding Source of the work is not available for anyone
+to copy, free of charge and under the terms of this License, through a
+publicly available network server or other readily accessible means,
+then you must either (1) cause the Corresponding Source to be so
+available, or (2) arrange to deprive yourself of the benefit of the
+patent license for this particular work, or (3) arrange, in a manner
+consistent with the requirements of this License, to extend the patent
+license to downstream recipients.  "Knowingly relying" means you have
+actual knowledge that, but for the patent license, your conveying the
+covered work in a country, or your recipient's use of the covered work
+in a country, would infringe one or more identifiable patents in that
+country that you have reason to believe are valid.
+
+  If, pursuant to or in connection with a single transaction or
+arrangement, you convey, or propagate by procuring conveyance of, a
+covered work, and grant a patent license to some of the parties
+receiving the covered work authorizing them to use, propagate, modify
+or convey a specific copy of the covered work, then the patent license
+you grant is automatically extended to all recipients of the covered
+work and works based on it.
+
+  A patent license is "discriminatory" if it does not include within
+the scope of its coverage, prohibits the exercise of, or is
+conditioned on the non-exercise of one or more of the rights that are
+specifically granted under this License.  You may not convey a covered
+work if you are a party to an arrangement with a third party that is
+in the business of distributing software, under which you make payment
+to the third party based on the extent of your activity of conveying
+the work, and under which the third party grants, to any of the
+parties who would receive the covered work from you, a discriminatory
+patent license (a) in connection with copies of the covered work
+conveyed by you (or copies made from those copies), or (b) primarily
+for and in connection with specific products or compilations that
+contain the covered work, unless you entered into that arrangement,
+or that patent license was granted, prior to 28 March 2007.
+
+  Nothing in this License shall be construed as excluding or limiting
+any implied license or other defenses to infringement that may
+otherwise be available to you under applicable patent law.
+
+  12. No Surrender of Others' Freedom.
+
+  If 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 convey a
+covered work so as to satisfy simultaneously your obligations under this
+License and any other pertinent obligations, then as a consequence you may
+not convey it at all.  For example, if you agree to terms that obligate you
+to collect a royalty for further conveying from those to whom you convey
+the Program, the only way you could satisfy both those terms and this
+License would be to refrain entirely from conveying the Program.
+
+  13. Use with the GNU Affero General Public License.
+
+  Notwithstanding any other provision of this License, you have
+permission to link or combine any covered work with a work licensed
+under version 3 of the GNU Affero General Public License into a single
+combined work, and to convey the resulting work.  The terms of this
+License will continue to apply to the part which is the covered work,
+but the special requirements of the GNU Affero General Public License,
+section 13, concerning interaction through a network will apply to the
+combination as such.
+
+  14. Revised Versions of this License.
+
+  The Free Software Foundation may publish revised and/or new versions of
+the GNU 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 that a certain numbered version of the GNU General
+Public License "or any later version" applies to it, you have the
+option of following the terms and conditions either of that numbered
+version or of any later version published by the Free Software
+Foundation.  If the Program does not specify a version number of the
+GNU General Public License, you may choose any version ever published
+by the Free Software Foundation.
+
+  If the Program specifies that a proxy can decide which future
+versions of the GNU General Public License can be used, that proxy's
+public statement of acceptance of a version permanently authorizes you
+to choose that version for the Program.
+
+  Later license versions may give you additional or different
+permissions.  However, no additional obligations are imposed on any
+author or copyright holder as a result of your choosing to follow a
+later version.
+
+  15. Disclaimer of Warranty.
+
+  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.
+
+  16. Limitation of Liability.
+
+  IN NO EVENT UNLESS REQUIRED BY APPLICABLE LAW OR AGREED TO IN WRITING
+WILL ANY COPYRIGHT HOLDER, OR ANY OTHER PARTY WHO MODIFIES AND/OR CONVEYS
+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.
+
+  17. Interpretation of Sections 15 and 16.
+
+  If the disclaimer of warranty and limitation of liability provided
+above cannot be given local legal effect according to their terms,
+reviewing courts shall apply local law that most closely approximates
+an absolute waiver of all civil liability in connection with the
+Program, unless a warranty or assumption of liability accompanies a
+copy of the Program in return for a fee.
+
+                     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
+state 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 3 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, see <http://www.gnu.org/licenses/>.
+
+Also add information on how to contact you by electronic and paper mail.
+
+  If the program does terminal interaction, make it output a short
+notice like this when it starts in an interactive mode:
+
+    <program>  Copyright (C) <year>  <name of author>
+    This program 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, your program's commands
+might be different; for a GUI interface, you would use an "about box".
+
+  You should also get your employer (if you work as a programmer) or school,
+if any, to sign a "copyright disclaimer" for the program, if necessary.
+For more information on this, and how to apply and follow the GNU GPL, see
+<http://www.gnu.org/licenses/>.
+
+  The GNU 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.  But first, please read
+<http://www.gnu.org/philosophy/why-not-lgpl.html>.
Index: /applications/editors/josm/plugins/epsg31287/README
===================================================================
--- /applications/editors/josm/plugins/epsg31287/README	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/README	(revision 23660)
@@ -0,0 +1,17 @@
+README 
+======
+
+ALPHA - use at own risk!
+
+A plugin for JOSM that sets current projection to EPSG:31287 - Bessel 1841 in Lambert_Conformal_Conic_2SP.
+
+AUTHORS and LICENSE:
+
+This plugin has been created by Fichtennadel (soskifub+josm at gmail), but depends heavily on 
+jhlabs Java Map Projection Library (http://www.jhlabs.com/java/maps/proj/), which is licensed
+under under the Apache License, Version 2.0.
+
+see http://wiki.openstreetmap.org/wiki/WikiProject_Austria/geoimage.at#JOSM_Plugin for details
+
+This plugin is licensed under the GNU GPL v3 or later.
+    
Index: /applications/editors/josm/plugins/epsg31287/build.xml
===================================================================
--- /applications/editors/josm/plugins/epsg31287/build.xml	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/build.xml	(revision 23660)
@@ -0,0 +1,260 @@
+<?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="epsg31287" default="dist" basedir=".">
+
+    <!-- enter the SVN commit message -->
+    <property name="commit.message" value="Commit message" />
+    <!-- enter the *lowest* JOSM version this plugin is currently compatible with -->
+    <property name="plugin.main.version" value="3592" />
+
+
+    <!--
+      ************************************************
+      ** should not be necessary to change the following properties
+     -->
+    <property name="josm"                   location="../../core/dist/josm-custom.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}" 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}">
+    		<!-- <zipfileset src="lib/javaproj-1.0.6.jar" /> -->
+            <!--
+        ************************************************
+        ** 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="Fichtennadel (soskifub+josm at gmail)"/>
+                <attribute name="Plugin-Class" value="org.openstreetmap.josm.plugins.epsg31287.Epsg31287"/>
+                <attribute name="Plugin-Date" value="${version.entry.commit.date}"/>
+                <attribute name="Plugin-Description" value="ALPHA - use at own risk - see link for docu &lt;br&gt; 
+                	                                        sets current projection to EPSG:31287 - Bessel 1841 in Lambert Conformal Conic 2SP &lt;br&gt;  
+                	                                        for use with WMS plugin to load geoimage.at WMS, see link for details"/>
+                <attribute name="Plugin-Link" value="http://wiki.openstreetmap.org/wiki/WikiProject_Austria/geoimage.at#JOSM_Plugin"/>
+                <attribute name="Plugin-Mainversion" value="${plugin.main.version}"/>
+                <!-- <attribute name="Plugin-Version" value="${version.entry.commit.revision}"/> -->
+            	<attribute name="Plugin-Version" value="0.3"/>
+            </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/epsg31287/src/com/jhlabs/map/AngleFormat.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/AngleFormat.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/AngleFormat.java	(revision 23660)
@@ -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/epsg31287/src/com/jhlabs/map/DegreeUnit.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/DegreeUnit.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/DegreeUnit.java	(revision 23660)
@@ -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/epsg31287/src/com/jhlabs/map/MapMath.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/MapMath.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/MapMath.java	(revision 23660)
@@ -0,0 +1,465 @@
+/*
+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.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);
+	}
+	
+	public static double normalizeLongitude(double angle) {
+		if (Double.isInfinite(angle) || Double.isNaN(angle))
+			throw new ProjectionException("Infinite longitude");
+		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/epsg31287/src/com/jhlabs/map/Unit.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/Unit.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/Unit.java	(revision 23660)
@@ -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/epsg31287/src/com/jhlabs/map/Units.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/Units.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/Units.java	(revision 23660)
@@ -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/epsg31287/src/com/jhlabs/map/proj/ConicProjection.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/ConicProjection.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/ConicProjection.java	(revision 23660)
@@ -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/epsg31287/src/com/jhlabs/map/proj/CylindricalProjection.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/CylindricalProjection.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/CylindricalProjection.java	(revision 23660)
@@ -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/epsg31287/src/com/jhlabs/map/proj/Ellipsoid.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/Ellipsoid.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/Ellipsoid.java	(revision 23660)
@@ -0,0 +1,168 @@
+/*
+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.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);
+    }
+
+    @Override
+    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;
+    }
+
+    @Override
+    public String toString() {
+        return name;
+    }
+}
Index: /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/LambertConformalConicProjection.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/LambertConformalConicProjection.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/LambertConformalConicProjection.java	(revision 23660)
@@ -0,0 +1,142 @@
+/*
+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.*;
+
+public class LambertConformalConicProjection extends ConicProjection {
+
+	private double n;
+	private double rho0;
+	private double c;
+
+	public LambertConformalConicProjection() {
+		minLatitude = Math.toRadians(0);
+		maxLatitude = Math.toRadians(80.0);
+		projectionLatitude = MapMath.QUARTERPI;
+		projectionLatitude1 = 0;
+		projectionLatitude2 = 0;
+		initialize();
+	}
+	
+	/**
+	* Set up a projection suitable for State Place Coordinates.
+	*/
+	public LambertConformalConicProjection(Ellipsoid ellipsoid, double lon_0, double lat_1, double lat_2, double lat_0, double x_0, double y_0) {
+		setEllipsoid(ellipsoid);
+		projectionLongitude = lon_0;
+		projectionLatitude = lat_0;
+		scaleFactor = 1.0;
+		falseEasting = x_0;
+		falseNorthing = y_0;
+		projectionLatitude1 = lat_1;
+		projectionLatitude2 = lat_2;
+		initialize();
+	}
+	
+	public Point2D.Double project(double x, double y, Point2D.Double out) {
+		double rho;
+		if (Math.abs(Math.abs(y) - MapMath.HALFPI) < 1e-10)
+			rho = 0.0;
+		else
+			rho = c * (spherical ? 
+			Math.pow(Math.tan(MapMath.QUARTERPI + .5 * y), -n) :
+			Math.pow(MapMath.tsfn(y, Math.sin(y), e), n));
+		out.x = scaleFactor * (rho * Math.sin(x *= n));
+		out.y = scaleFactor * (rho0 - rho * Math.cos(x));
+		return out;
+	}
+
+	public Point2D.Double projectInverse(double x, double y, Point2D.Double out) {
+		x /= scaleFactor;
+		y /= scaleFactor;
+		double rho = MapMath.distance(x, y = rho0 - y);
+		if (rho != 0) {
+			if (n < 0.0) {
+				rho = -rho;
+				x = -x;
+				y = -y;
+			}
+			if (spherical)
+				out.y = 2.0 * Math.atan(Math.pow(c / rho, 1.0/n)) - MapMath.HALFPI;
+			else
+				out.y = MapMath.phi2(Math.pow(rho / c, 1.0/n), e);
+			out.x = Math.atan2(x, y) / n;
+		} else {
+			out.x = 0.0;
+			out.y = n > 0.0 ? MapMath.HALFPI : -MapMath.HALFPI;
+		}
+		return out;
+	}
+
+	public void initialize() {
+		super.initialize();
+		double cosphi, sinphi;
+		boolean secant;
+
+		if ( projectionLatitude1 == 0 )
+			projectionLatitude1 = projectionLatitude2 = projectionLatitude;
+
+		if (Math.abs(projectionLatitude1 + projectionLatitude2) < 1e-10)
+			throw new ProjectionException();
+		n = sinphi = Math.sin(projectionLatitude1);
+		cosphi = Math.cos(projectionLatitude1);
+		secant = Math.abs(projectionLatitude1 - projectionLatitude2) >= 1e-10;
+		spherical = (es == 0.0);
+		if (!spherical) {
+			double ml1, m1;
+
+			m1 = MapMath.msfn(sinphi, cosphi, es);
+			ml1 = MapMath.tsfn(projectionLatitude1, sinphi, e);
+			if (secant) {
+				n = Math.log(m1 /
+				   MapMath.msfn(sinphi = Math.sin(projectionLatitude2), Math.cos(projectionLatitude2), es));
+				n /= Math.log(ml1 / MapMath.tsfn(projectionLatitude2, sinphi, e));
+			}
+			c = (rho0 = m1 * Math.pow(ml1, -n) / n);
+			rho0 *= (Math.abs(Math.abs(projectionLatitude) - MapMath.HALFPI) < 1e-10) ? 0. :
+				Math.pow(MapMath.tsfn(projectionLatitude, Math.sin(projectionLatitude), e), n);
+		} else {
+			if (secant)
+				n = Math.log(cosphi / Math.cos(projectionLatitude2)) /
+				   Math.log(Math.tan(MapMath.QUARTERPI + .5 * projectionLatitude2) /
+				   Math.tan(MapMath.QUARTERPI + .5 * projectionLatitude1));
+			c = cosphi * Math.pow(Math.tan(MapMath.QUARTERPI + .5 * projectionLatitude1), n) / n;
+			rho0 = (Math.abs(Math.abs(projectionLatitude) - MapMath.HALFPI) < 1e-10) ? 0. :
+				c * Math.pow(Math.tan(MapMath.QUARTERPI + .5 * projectionLatitude), -n);
+		}
+	}
+	
+	/**
+	 * Returns true if this projection is conformal
+	 */
+	public boolean isConformal() {
+		return true;
+	}
+
+	public boolean hasInverse() {
+		return true;
+	}
+
+	public String toString() {
+		return "Lambert Conformal Conic";
+	}
+
+}
+
Index: /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/Projection.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/Projection.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/Projection.java	(revision 23660)
@@ -0,0 +1,748 @@
+/*
+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 map projections
+ */
+public class Projection implements Cloneable {
+
+	/**
+	 * 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;
+
+	/**
+	 * 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;
+
+	/**
+	 * 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 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;
+	}
+
+	/**
+	 * The method which actually does the projection. This should be overridden for all projections.
+	 */
+	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;
+	}
+
+	/**
+	 * 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;
+	}
+	
+	/**
+	 * 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
+	 */
+	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/long point is visible in this projection
+	 */
+	public boolean inside(double x, double y) {
+		x = normalizeLongitude( (float)(x*DTR-projectionLongitude) );
+		return minLongitude <= x && x <= maxLongitude && minLatitude <= y && y <= 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();
+	}
+
+	/**
+	 * 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 = normalizeLongitudeRadians( 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 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;
+	}
+	
+	/**
+	 * 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;		
+	}
+
+	public static float normalizeLongitude(float angle) {
+		if ( Double.isInfinite(angle) || Double.isNaN(angle) )
+			throw new IllegalArgumentException("Infinite longitude");
+		while (angle > 180)
+			angle -= 360;
+		while (angle < -180)
+			angle += 360;
+		return angle;
+	}
+
+	public static double normalizeLongitudeRadians( double angle ) {
+		if ( Double.isInfinite(angle) || Double.isNaN(angle) )
+			throw new IllegalArgumentException("Infinite longitude");
+		while (angle > Math.PI)
+			angle -= MapMath.TWOPI;
+		while (angle < -Math.PI)
+			angle += MapMath.TWOPI;
+		return angle;
+	}
+
+}
+
Index: /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/ProjectionException.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/ProjectionException.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/ProjectionException.java	(revision 23660)
@@ -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/epsg31287/src/com/jhlabs/map/proj/ProjectionFactory.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/ProjectionFactory.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/ProjectionFactory.java	(revision 23660)
@@ -0,0 +1,388 @@
+/*
+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.io.*;
+import java.util.*;
+import java.awt.geom.*;
+import com.jhlabs.map.*;
+
+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.setProjectionLatitude1Degrees( parseAngle( s ) );
+        s = (String)params.get( "lat_2" );
+        if ( s != null )
+            projection.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();
+    }
+
+    static Hashtable registry;
+
+    static void register( String name, Class cls, String description ) {
+        registry.put( name, cls );
+    }
+
+    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 );
+                return projection;
+            }
+            catch ( IllegalAccessException e ) {
+                e.printStackTrace();
+            }
+            catch ( InstantiationException e ) {
+                e.printStackTrace();
+            }
+        }
+        return null;
+    }
+
+    static void initialize() {
+        registry = new Hashtable();
+        register( "lcc", LambertConformalConicProjection.class, "Lambert Conformal Conic" );
+    }
+
+    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/epsg31287/src/com/jhlabs/map/proj/TransverseMercatorProjection.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/TransverseMercatorProjection.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/com/jhlabs/map/proj/TransverseMercatorProjection.java	(revision 23660)
@@ -0,0 +1,227 @@
+/*
+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.
+ *
+ * Bernhard Jenny, February 2 2010: Corrected code for spherical case in
+ * projectInverse, added isConformal.
+ * 27 September 2010: added missing tests to forward spherical, removed
+ * initialization code in constructor.
+ */
+package com.jhlabs.map.proj;
+
+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() {
+        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 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) {
+            final double cosphi = Math.cos(lpphi);
+            double b = cosphi * Math.sin(lplam);
+            if (Math.abs(Math.abs(b) - 1.) <= EPS10) {
+                throw new ProjectionException("F_ERROR"); // FIXME F_ERROR macro returns 0/0 and error -20
+            }
+
+            xy.x = ml0 * scaleFactor * Math.log((1. + b) / (1. - b));
+            xy.y = cosphi * Math.cos(lplam) / Math.sqrt(1. - b * b);
+            b = Math.abs(xy.y);
+            if (b >= 1.) {
+                if ((b - 1.) > EPS10) {
+                    throw new ProjectionException("F_ERROR"); // FIXME F_ERROR macro returns 0/0 and error -20
+                } else {
+                    xy.y = 0.;
+                }
+            } else {
+                xy.y = MapMath.acos(xy.y);
+            }
+            if (lpphi < 0.0) {
+                xy.y = -xy.y;
+            }
+            xy.y = esp * (xy.y - 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 boolean isRectilinear() {
+        return false;
+    }
+    
+    public String toString() {
+        return "Transverse Mercator";
+    }
+}
Index: /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/EPSG31287UploadHook.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/EPSG31287UploadHook.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/EPSG31287UploadHook.java	(revision 23660)
@@ -0,0 +1,27 @@
+//License: GPL. For details, see README file.
+
+package org.openstreetmap.josm.plugins.epsg31287;
+
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.upload.UploadHook;
+import org.openstreetmap.josm.data.APIDataSet;
+
+public class EPSG31287UploadHook implements UploadHook {
+
+    private final Epsg31287 plugin;
+
+    public EPSG31287UploadHook(Epsg31287 plugin)
+    {
+        this.plugin = plugin;
+    }
+
+    @Override
+    public boolean checkUpload(APIDataSet arg0) {
+        if (Main.proj.toCode().equals(ProjectionEPSG31287.getProjCode())) {
+            plugin.toggleProjection();
+        }
+        return true;
+    }
+
+}
Index: /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/Epsg31287.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/Epsg31287.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/Epsg31287.java	(revision 23660)
@@ -0,0 +1,123 @@
+//License: GPL. For details, see README file.
+
+package org.openstreetmap.josm.plugins.epsg31287;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+import static org.openstreetmap.josm.tools.I18n.marktr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+
+import javax.swing.JMenu;
+import javax.swing.JMenuItem;
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.actions.JosmAction;
+import org.openstreetmap.josm.actions.UploadAction;
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.projection.Mercator;
+import org.openstreetmap.josm.data.projection.Projection;
+import org.openstreetmap.josm.gui.MainMenu;
+import org.openstreetmap.josm.gui.preferences.ProjectionPreference;
+import org.openstreetmap.josm.plugins.Plugin;
+import org.openstreetmap.josm.plugins.PluginInformation;
+
+public class Epsg31287 extends Plugin {
+
+    private JMenu mMenu;
+    private Projection oldProj;
+    private final String projCode;
+
+    public Epsg31287(PluginInformation info) {
+        super(info);
+        projCode = ProjectionEPSG31287.getProjCode();
+        refreshMenu();
+    }
+
+    public void toggleProjection()
+    {
+        Bounds b = (Main.map != null && Main.map.mapView != null) ? Main.map.mapView.getRealBounds() : null;
+
+        try {
+            // toggle projection
+            if (Main.proj.toCode().equals(projCode)) {
+                // use JOSM built in to fire Listeners
+                ProjectionPreference.setProjection(oldProj.getClass().getName(), null);
+
+                //Main.proj = oldProj;
+                //UploadAction.unregisterUploadHook(uploadHook);
+                //uploadHook = null;
+            } else {
+                oldProj = Main.proj;
+                Main.proj = new ProjectionEPSG31287();
+                //TODO use JOSM built in to fire Listeners, does not work currently due to classnotfound ex
+                //     ProjectionPreference.setProjection(ProjectionEPSG31287.class.getName(), null);
+                UploadAction.registerUploadHook(new EPSG31287UploadHook(this));
+            }
+            // toggle Menu
+            refreshMenu();
+            // show info
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("Current projection is set to {0}", Main.proj.toString()) +
+                    (Main.proj.toCode().equals(projCode) ?
+                            tr("\nPlease adjust WMS layer manually by using known exact objects/traces/... before starting to map")
+                            : ""),
+                            tr("Info"),
+                            JOptionPane.INFORMATION_MESSAGE
+            );
+        } catch (final Exception e) {
+            JOptionPane.showMessageDialog(
+                    Main.parent,
+                    tr("The projection {0} could not be activated. Using Mercator", projCode),
+                    tr("Error"),
+                    JOptionPane.ERROR_MESSAGE
+            );
+            Main.proj = new Mercator();
+        }
+        if((b != null) && (oldProj != null) && (!Main.proj.getClass().getName().equals(oldProj.getClass().getName()) || Main.proj.hashCode() != oldProj.hashCode()))
+        {
+            Main.map.mapView.zoomTo(b);
+            /* TODO - remove layers with fixed projection */
+        }
+    }
+
+    public void refreshMenu() {
+        MainMenu menu = Main.main.menu;
+
+        if (mMenu == null)
+            mMenu = menu.addMenu(marktr("EPSG31287"), KeyEvent.VK_S, menu.defaultMenuPos, null);
+        else
+            mMenu.removeAll();
+        // toggle menu text based on current projection
+        if (Main.proj.toCode().equals(projCode)) {
+            mMenu.add(new JMenuItem(new
+                    JosmAction(tr("set {0}",oldProj.toString())
+                            ,"wmsmenu.png"
+                            ,tr("set projection from {0} to {1}",projCode,oldProj.toString())
+                            , null, false)
+            {
+                private static final long serialVersionUID = 7610502878925107647L;
+                @Override
+                public void actionPerformed(ActionEvent ev) {
+                    toggleProjection();
+                }
+            }));
+        } else {
+            mMenu.add(new JMenuItem(new
+                    JosmAction(tr("set {0}",projCode)
+                            ,"wmsmenu_off.png"
+                            ,tr("set projection from {0} to {1}",Main.proj.toString() ,projCode)
+                            , null, false)
+            {
+                private static final long serialVersionUID = 7610502878925107646L;
+                @Override
+                public void actionPerformed(ActionEvent ev) {
+                    toggleProjection();
+                }
+            }));
+        }
+    }
+
+}
Index: /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/ProjectionEPSG31287.java
===================================================================
--- /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/ProjectionEPSG31287.java	(revision 23660)
+++ /applications/editors/josm/plugins/epsg31287/src/org/openstreetmap/josm/plugins/epsg31287/ProjectionEPSG31287.java	(revision 23660)
@@ -0,0 +1,164 @@
+//License: GPL. For details, see README file.
+
+package org.openstreetmap.josm.plugins.epsg31287;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.util.Collection;
+import java.util.Arrays;
+
+import javax.swing.JPanel;
+import javax.swing.JLabel;
+import javax.swing.JTextField;
+import java.awt.GridBagLayout;
+import java.awt.geom.Point2D;
+
+import org.openstreetmap.josm.data.Bounds;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.tools.GBC;
+
+public class ProjectionEPSG31287 implements org.openstreetmap.josm.data.projection.Projection, org.openstreetmap.josm.data.projection.ProjectionSubPrefs {
+
+    private double dx = 85.0;
+    private double dy = 45.0;
+    private final static String projCode = "EPSG:31287";
+
+    private final com.jhlabs.map.proj.Projection projection;
+
+    public ProjectionEPSG31287() {
+        super();
+        // use use com.jhlabs.map.proj.ProjectionFactory for doing all the math
+        projection = com.jhlabs.map.proj.ProjectionFactory.fromPROJ4Specification(
+                new String[] {
+                        "+proj=lcc"
+                        ,"+lat_1=49"
+                        ,"+lat_2=46"
+                        ,"+lat_0=47.5"
+                        ,"+lon_0=13.33333333333333"
+                        ,"+x_0=400000"
+                        ,"+y_0=400000"
+                        ,"+ellps=bessel"
+                        ,"+towgs84=577.326,90.129,463.919,5.137,1.474,5.297,2.4232"
+                        ,"+units=m"
+                        ,"+no_defs"
+                }
+        );
+    }
+
+    // PreferencePanel, not used in plugin mode, useful for JOSM custom-build
+    @Override
+    public void setupPreferencePanel(JPanel p) {
+        //p.add(new HtmlPanel("<i>EPSG:31287 - Bessel 1841 in Lambert_Conformal_Conic_2SP</i>"), GBC.eol().fill(GBC.HORIZONTAL));
+        //p.add(Box.createVerticalGlue(), GBC.eol().fill(GBC.BOTH));
+        p.setLayout(new GridBagLayout());
+
+        JTextField gdx = new JTextField(""+dx);
+        JTextField gdy = new JTextField(""+dy);
+
+        p.add(new JLabel(tr("dx")), GBC.std().insets(5,5,0,5));
+        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(gdx, GBC.eop().fill(GBC.HORIZONTAL));
+
+        p.add(new JLabel(tr("dy")), GBC.std().insets(5,5,0,5));
+        p.add(GBC.glue(1, 0), GBC.std().fill(GBC.HORIZONTAL));
+        p.add(gdy, GBC.eop().fill(GBC.HORIZONTAL));
+        p.add(GBC.glue(1, 1), GBC.eol().fill(GBC.BOTH));
+
+    }
+
+    // for PreferencePanel, not used in plugin mode, useful for JOSM custom-build
+    @Override
+    public Collection<String> getPreferences(JPanel p) {
+        dx = new Double(((JTextField)p.getComponent(2)).getText());
+        dy = new Double(((JTextField)p.getComponent(5)).getText());
+        return Arrays.asList(""+dx,""+dy);
+    }
+
+    // for PreferencePanel, not used in plugin mode, useful for JOSM custom-build
+    @Override
+    public Collection<String> getPreferencesFromCode(String code) {
+        dx = 85.0;
+        dy = 45.0;
+        return null;
+    }
+
+    // for PreferencePanel, not used in plugin mode, useful for JOSM custom-build
+    @Override
+    public void setPreferences(Collection<String> args) {
+        if(args != null)
+        {
+            String[] array = args.toArray(new String[0]);
+            if (array.length > 0) {
+                try {
+                    dx = Double.parseDouble(array[0]);
+                } catch(NumberFormatException e) {}
+            }
+            if (array.length > 1) {
+                try {
+                    dy = Double.parseDouble(array[1]);
+                } catch(NumberFormatException e) {}
+            }
+        }
+    }
+
+    @Override
+    public double getDefaultZoomInPPD() {
+        return 1.01;
+    }
+
+    /**
+     * @param LatLon WGS84 (in degree)
+     * @return xy epsg31287 east/north (in meters)
+     */
+    @Override
+    public EastNorth latlon2eastNorth(LatLon p) {
+        Point2D.Double c = new Point2D.Double();
+        c.x = p.lon();
+        c.y = p.lat();
+        //System.out.println("From " + c.x + " " + c.y);
+        projection.transform( c, c );
+        //System.out.println("To " + c.x + " " + c.y);
+        return new EastNorth(c.x+dx, c.y+dy);
+    }
+
+    /**
+     * @param xy epsg31287 east/north (in meters)
+     * @return LatLon WGS84 (in degree)
+     */
+    @Override
+    public LatLon eastNorth2latlon(EastNorth p) {
+        Point2D.Double c = new Point2D.Double();
+        c.x = p.east()-dx;
+        c.y = p.north()-dy;
+        //System.out.println("InvFrom " + c.x + " " + c.y);
+        projection.inverseTransform( c, c );
+        //System.out.println("InvTo " + c.x + " " + c.y);
+        return new LatLon(c.y, c.x);
+    }
+
+    @Override
+    public String toString() {
+        return tr(projCode + " - Bessel 1841 in Lambert Conformal Conic");
+    }
+
+    @Override
+    public String toCode() {
+        return projCode;
+    }
+
+    @Override
+    public String getCacheDirectoryName() {
+        return "EPSG_31287";
+    }
+
+    @Override
+    public Bounds getWorldBoundsLatLon() {
+        return new Bounds(new LatLon(45.4, 8.7), new LatLon(49.4, 17.5));
+    }
+
+    public static String getProjCode() {
+        return projCode;
+    }
+
+}
