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.
- 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.
from javax.swing import JOptionPane from org.openstreetmap.josm import Main from org.openstreetmap.josm.data import osm import org.openstreetmap.josm.command as Command if Main.main and Main.main.map : mv = Main.main.map.mapView if mv and mv.editLayer and mv.editLayer.data : sel = mv.editLayer.data.getSelected() old = sel 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.
(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"))))