From OpenStreetMap Wiki
Jump to navigation Jump to search

Mapping Interests

Live in Leuven but regularly find myself in Antwerp, so I work a bit on both cities. Also interested in mapping scuba diving sites in Belgium. I also map when traveling and have added hiking trails in Laos and ski slopes in New Mexico, USA.


Holux M-241

Android GSM running Maverick, but open to suggestions for better software.

JOSM Scripting

  • See here
  • Under Linux, standard output from scripts is printed in the terminal in which JOSM is started.


The examples on the Scripting plugin page are fairly rudimentary, so here's a slightly longer one showing how to edit a node. The API is essentially the internal JOSM API.

Tag Node

from javax.swing import JOptionPane
from org.openstreetmap.josm import Main
from import osm
import org.openstreetmap.josm.command as Command

if Main.main and :
  mv =

if mv and mv.editLayer and :
  sel =
  old = sel[0]
  assert type(old) == osm.Node
  new = osm.Node(old)
  new.put("FIXME", "This node is wrong")
  Main.main.undoRedo.add(Command.SequenceCommand("Python Script", [Command.ChangeCommand(old, new)]))


Armed Bear Common Lisp (ABCL) provides a JSR-223 compatible engine, allowing one to script in Common Lisp. Java functions cannot be called directly as Lisp functions, however, and are only accessible via the ABCL FFI, as below.

It would seem that JOSM maintains a single, continuous instance of each scripting engine, judging from some of the "Warning: redefined" messages abcl outputs while running as a scripting engine. This means that common functions could be defined in a separate library and loaded at startup.

Hello, World

(let ((JOptionPane (jclass "javax.swing.JOptionPane"))
      (Component   (jclass "java.awt.Component"))
      (Object      (jclass "java.lang.Object"))
      (Main        (jclass "org.openstreetmap.josm.Main"))
      (MapView     (jclass "org.openstreetmap.josm.gui.MapView")))
  (let* ((wparent (jfield Main "parent"))
         (inst    (jfield Main "main"))
         (frame   (and inst  (jfield "map" inst)))
         (view    (and frame (jfield "mapView" frame))))
    (let ((showMessageDialog (jmethod JOptionPane "showMessageDialog" Component Object))
          (getNumLayers      (jmethod MapView     "getNumLayers")))
      (jstatic showMessageDialog () wparent (if view (format () "[Lisp] Hello World! You have ~D layer(s)." (jcall getNumLayers view)) "No map view found")))))

The lets are here to make the workflow clearer. Two pitfalls worth noting:

  • abcl is case-insensitive, so don't assign "Main.main..." to the variable "main"
  • It seems to be essential to know whether or not a member variable of a class is static

Here is a slightly more lispy version:

(defun tryjfield (inst name)
  (and inst (jfield name inst)))

(let* ((Main (jclass "org.openstreetmap.josm.Main"))
       (view (tryjfield (tryjfield (jfield Main "main") "map") "mapView")))
  (flet ((show-message-dialog (parent content)
                              (jstatic (jmethod (jclass "javax.swing.JOptionPane") "showMessageDialog" (jclass "java.awt.Component") (jclass "java.lang.Object"))
                                       () parent content))
         (get-num-layers (inst) (jcall (jmethod (jclass "org.openstreetmap.josm.gui.MapView") "getNumLayers") inst)))
    (show-message-dialog (jfield Main "parent") (if view (format () "[Lisp] Hello World! You have ~D layer(s)." (get-num-layers view)) "No map view found"))))