[OSM-dev] [PATCH] JOSM - make reorder command work better.

Robert Hart bathterror at gmail.com
Wed Aug 29 10:38:28 BST 2007


(reposted with patch inline - I think mailing list doesn't like attachments)

The patch below is a first attempt to fix problems with the reorder
tool in JOSM not acting as expected. With this patch the reorder tool
should work on a wider range of ways, particularly ways with loops at
the start and end, and should prefer the existing order when a way is
already sorted (I think). The behaviour with branched ways remains
undefined.

There are two parts to the fix:

1) Prefer to move forward from the end of the segment to the start of
the next. (specifically this prevents certain case where a correctly
ordered way would be scrambled by the reorder tool, by nipping the
wrong way down a loop but then continuing forward the correct way
around the loop.

2) Try and start from a segment that is likely to be at the start of the way.

The logic goes: For each of the nodes in the way count up how many
times it occurs as the start or end node of a segment in the way. Then
pick the first segment that has:
a) a start node used only once (i.e. most common ways)
b) a start node used an odd number of times (e.g. a way with a lollipop loop)
c) an end node used only once (e.g. a partially reversed way)
d) an end node used an odd number of times. (e.g. a partially reversed lollipop)
otherwise pick the first segment (e.g. closed loop)

Logically a non-branched way should contain either exactly two nodes
with odd reference counts or none.

This is related to trac#169, but not an entire fix yet as the reorder
logic is separate for tools that modify ways - I'll look into that
later.

 I don't write much java, so my perl mentality is probably shining
through a bit too much - feel free to complain and I'll try and
address any concerns.

Rob

Index: src/org/openstreetmap/josm/actions/ReorderAction.java
===================================================================
--- src/org/openstreetmap/josm/actions/ReorderAction.java	(revision 314)
+++ src/org/openstreetmap/josm/actions/ReorderAction.java	(working copy)
@@ -9,6 +9,7 @@
 import java.util.Collection;
 import java.util.Iterator;
 import java.util.LinkedList;
+import java.util.HashMap;

 import javax.swing.JOptionPane;

@@ -172,28 +173,102 @@
 		
 		while (!segments.isEmpty()) {
 			LinkedList<Segment> pivotList = new LinkedList<Segment>();
-			pivotList.add(segments.getFirst());
-			segments.removeFirst();
+			pivotList.add(firstSegment(segments));
+			segments.remove(pivotList.getLast());
 			boolean found;
 			do {
 				found = false;
+				//try working forwards first
 				for (Iterator<Segment> it = segments.iterator(); it.hasNext();) {
 					Segment ls = it.next();
 					if (ls.incomplete)
 						continue; // incomplete segments are never added to a new way
-					if (ls.from == pivotList.getLast().to || (!strict && (ls.to ==
pivotList.getLast().to || ls.from == pivotList.getLast().from || ls.to
== pivotList.getLast().from))) {
+					if (ls.from == pivotList.getLast().to) {
 						pivotList.addLast(ls);
 						it.remove();
 						found = true;
+					}
+				}
+				if(!found){
+				    for (Iterator<Segment> it = segments.iterator(); it.hasNext();) {
+					Segment ls = it.next();
+					if (ls.incomplete)
+					    continue; // incomplete segments are never added to a new way
+					if (ls.from == pivotList.getLast().to || (!strict && (ls.to ==
pivotList.getLast().to || ls.from == pivotList.getLast().from || ls.to
== pivotList.getLast().from))) {
+					    pivotList.addLast(ls);
+					    it.remove();
+					    found = true;
 					} else if (ls.to == pivotList.getFirst().from || (!strict &&
(ls.from == pivotList.getFirst().from || ls.to ==
pivotList.getFirst().to || ls.from == pivotList.getFirst().to))) {
-						pivotList.addFirst(ls);
-						it.remove();
-						found = true;
+					    pivotList.addFirst(ls);
+					    it.remove();
+					    found = true;
 					}
+				    }
 				}
 			} while (found);
 			sortedSegments.addAll(pivotList);
 		}
 	    return sortedSegments;
 	}
+
+    /* This method searches for a good segment to start a reorder from.
+     * In most cases this will be a segment with a start node that occurs only
+     * once in the way. In cases with loops, this could be any odd
number. If no nodes
+     * are referenced an odd number of times, then any segment is a
good start point.
+     */
+	public static Segment firstSegment(LinkedList<Segment> segments) {
+	    HashMap refCount = new HashMap(segments.size()*2);
+	    //loop through all segments and count up how many times each
node is referenced
+	    for (Iterator<Segment> it = segments.iterator(); it.hasNext();) {
+		Segment seg = it.next();
+		int c;
+		Node node;
+
+		node = seg.from;
+		if(refCount.containsKey(node)){
+		    c = ((Integer)refCount.get(node)).intValue();
+		} else {
+		    c = 0;
+		}
+		refCount.put(node,new Integer(c+1));
+
+		node = seg.to;
+		if(refCount.containsKey(node)){
+		    c = ((Integer)refCount.get(node)).intValue();
+		} else {
+		    c = 0;
+		}
+		refCount.put(node,new Integer(c+1));
+	    }
+	    //now look for start nodes that are referenced only once
+	    for (Iterator<Segment> it = segments.iterator(); it.hasNext();) {
+		Segment seg = it.next();
+		int c;
+		c = ((Integer)refCount.get(seg.from)).intValue();
+		if(c==1) return seg;
+	    }
+	    //now look for start nodes that are referenced only (2n+1)
+	    for (Iterator<Segment> it = segments.iterator(); it.hasNext();) {
+		Segment seg = it.next();
+		int c;
+		c = ((Integer)refCount.get(seg.from)).intValue();
+		if((c%2)==1) return seg;
+	    }
+	    //now look for end nodes that are referenced only once
+	    for (Iterator<Segment> it = segments.iterator(); it.hasNext();) {
+		Segment seg = it.next();
+		int c;
+		c = ((Integer)refCount.get(seg.to)).intValue();
+		if(c==1) return seg;
+	    }
+	    //now look for end nodes that are referenced only (2n+1)
+	    for (Iterator<Segment> it = segments.iterator(); it.hasNext();) {
+		Segment seg = it.next();
+		int c;
+		c = ((Integer)refCount.get(seg.to)).intValue();
+		if((c%2)==1) return seg;
+	    }
+
+	    return segments.getFirst();
+	}
 }


-- 
-- 
Robert Hart




More information about the dev mailing list