[OSM-dev] Two patches for JOSM - Align in {circle,line}
matthew-osm at newtoncomputing.co.uk
matthew-osm at newtoncomputing.co.uk
Mon Oct 23 03:27:14 BST 2006
Used the wrong from address... try again ;-)
----- Forwarded message from Me -----
To: Immanuel Scholz <immanuel.scholz at gmx.de>
Cc: dev at openstreetmap.org, clive at tux-it.co.uk
Subject: Two patches for JOSM - Align in {circle,line}
Hi Imi,
I've created two patches for JOSM here. The first is a very small bugfix for my
align-in-circle patch that stops the selection being cleared at the end of the
function. This was a mistake left over from some debug code. It is in the
attached josm166_circle_bugfix.patch file, and uploaded to your trac, number 39.
The second patch is for a new similar feature that aligns nodes into a straight
line. This is intended for (careful) use when a straight road has side-roads
leading off. The additional nodes along the straight road that are necessary for
the side-roads can cause the straight road to become non-straight very easily.
This feature moves all nodes that are between the two most-distant nodes onto
the line between the most distant nodes.
How's that for a badly worded explanation ;-).
Anyway, attached as josm166_align_in_line.patch and uploaded to your trac,
number 40. You might find a better way than the current double loop... I'd do
for (a=0; a < nodes.size() - 1; a++) {
for (b = a + 1; b < nodes.size(); b++) {
/* use nodes[a] and nodes[b] */
...
}
}
in C, but I can't work out how to do it in Java. Therefore I added all nodes to
two collections, "nodes" and "itnodes", and then removed nodes from "itnodes"
one by one in the outer loop. I don't like it, as it's a waste of memory, but
I am sure you know a much better way of doing it!
Both patches apply to revision 166 in SVN.
Hope they're OK! *
Thanks,
--
Matthew
* Sorry, checking now and I think some tabs slipped through, so indentation may
be a bit iffy.
-------------- next part --------------
Index: src/org/openstreetmap/josm/actions/AlignInLineAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInLineAction.java (revision 0)
+++ src/org/openstreetmap/josm/actions/AlignInLineAction.java (revision 0)
@@ -0,0 +1,117 @@
+package org.openstreetmap.josm.actions;
+
+import static org.openstreetmap.josm.tools.I18n.tr;
+
+import java.awt.event.ActionEvent;
+import java.awt.event.KeyEvent;
+import java.util.Collection;
+import java.util.LinkedList;
+
+import javax.swing.JOptionPane;
+
+import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.command.Command;
+import org.openstreetmap.josm.command.MoveCommand;
+import org.openstreetmap.josm.command.SequenceCommand;
+import org.openstreetmap.josm.data.coor.EastNorth;
+import org.openstreetmap.josm.data.coor.LatLon;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.OsmPrimitive;
+
+/**
+ * Aligns all selected nodes into a straight line (useful for
+ * roads that should be straight, but have side roads and
+ * therefore need multiple nodes)
+ *
+ * @author Matthew Newton
+ */
+public final class AlignInLineAction extends JosmAction {
+
+ public AlignInLineAction() {
+ super(tr("Align Nodes in Line"), "clock", tr("Move the selected nodes onto a line."), KeyEvent.VK_L, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK);
+ }
+
+ public void actionPerformed(ActionEvent e) {
+/**
+ * The general algorithm here is to find the two selected nodes
+ * that are furthest apart, and then to align all other selected
+ * nodes onto the straight line between these nodes.
+ */
+ Collection<OsmPrimitive> sel = Main.ds.getSelected();
+ Collection<Node> nodes = new LinkedList<Node>();
+ Collection<Node> itnodes = new LinkedList<Node>();
+ for (OsmPrimitive osm : sel)
+ if (osm instanceof Node) {
+ nodes.add((Node)osm);
+ itnodes.add((Node)osm);
+ }
+ if (nodes.size() < 3) {
+ JOptionPane.showMessageDialog(Main.parent, tr("Please select at least three nodes."));
+ return;
+ }
+
+ // Find from the selected nodes two that are the furthest apart.
+ // Let's call them A and B.
+ double distance = 0;
+
+ Node nodea = null;
+ Node nodeb = null;
+
+ for (Node n : nodes) {
+ itnodes.remove(n);
+ for (Node m : itnodes) {
+ double dist = Math.sqrt(n.eastNorth.distance(m.eastNorth));
+ if (dist > distance) {
+ nodea = n;
+ nodeb = m;
+ distance = dist;
+ }
+ }
+ }
+
+ // Remove the nodes A and B from the list of nodes to move
+ nodes.remove(nodea);
+ nodes.remove(nodeb);
+
+ // Find out co-ords of A and B
+ double ax = nodea.eastNorth.east();
+ double ay = nodea.eastNorth.north();
+ double bx = nodeb.eastNorth.east();
+ double by = nodeb.eastNorth.north();
+
+ // A list of commands to do
+ Collection<Command> cmds = new LinkedList<Command>();
+
+ // OK, for each node to move, work out where to move it!
+ for (Node n : nodes) {
+ // Get existing co-ords of node to move
+ double nx = n.eastNorth.east();
+ double ny = n.eastNorth.north();
+
+ if (ax == bx) {
+ // Special case if AB is vertical...
+ nx = ax;
+ } else if (ay == by) {
+ // ...or horizontal
+ ny = ay;
+ } else {
+ // Otherwise calculate position by solving y=mx+c
+ double m1 = (by - ay) / (bx - ax);
+ double c1 = ay - (ax * m1);
+ double m2 = (-1) / m1;
+ double c2 = n.eastNorth.north() - (n.eastNorth.east() * m2);
+
+ nx = (c2 - c1) / (m1 - m2);
+ ny = (m1 * nx) + c1;
+ }
+
+ // Add the command to move the node to its new position.
+ cmds.add(new MoveCommand(n, nx - n.eastNorth.east(), ny - n.eastNorth.north() ));
+ }
+
+ // Do it!
+ Main.main.editLayer().add(new SequenceCommand(tr("Align Nodes in Line"), cmds));
+
+ Main.map.repaint();
+ }
+}
Index: src/org/openstreetmap/josm/gui/MainMenu.java
===================================================================
--- src/org/openstreetmap/josm/gui/MainMenu.java (revision 166)
+++ src/org/openstreetmap/josm/gui/MainMenu.java (working copy)
@@ -9,6 +9,7 @@
import org.openstreetmap.josm.actions.AboutAction;
import org.openstreetmap.josm.actions.AlignInCircleAction;
+import org.openstreetmap.josm.actions.AlignInLineAction;
import org.openstreetmap.josm.actions.DownloadAction;
import org.openstreetmap.josm.actions.DownloadIncompleteAction;
import org.openstreetmap.josm.actions.ExitAction;
@@ -40,6 +41,7 @@
public final DownloadAction download = new DownloadAction();
public final Action reverseSegment = new ReverseSegmentAction();
public final Action alignInCircle = new AlignInCircleAction();
+ public final Action alignInLine = new AlignInLineAction();
public final Action upload = new UploadAction();
public final Action save = new SaveAction();
public final Action saveAs = new SaveAsAction();
@@ -75,6 +77,7 @@
editMenu.addSeparator();
editMenu.add(reverseSegment);
editMenu.add(alignInCircle);
+ editMenu.add(alignInLine);
editMenu.addSeparator();
editMenu.add(preferences);
add(editMenu);
-------------- next part --------------
Index: src/org/openstreetmap/josm/actions/AlignInCircleAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/AlignInCircleAction.java (revision 166)
+++ src/org/openstreetmap/josm/actions/AlignInCircleAction.java (working copy)
@@ -67,7 +67,6 @@
}
Main.main.editLayer().add(new SequenceCommand(tr("Align Nodes in Circle"), cmds));
- Main.ds.setSelected(avn);
Main.map.repaint();
}
}
More information about the dev
mailing list