Index: /.classpath
===================================================================
--- /.classpath	(revision 48)
+++ /.classpath	(revision 49)
@@ -6,4 +6,5 @@
 	<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
 	<classpathentry sourcepath="/home/imi/src/jdom-1.0/src" kind="lib" path="lib/jdom.jar"/>
+	<classpathentry sourcepath="JUNIT_SRC_HOME/junitsrc.zip" kind="var" path="JUNIT_HOME/junit.jar"/>
 	<classpathentry kind="output" path="bin"/>
 </classpath>
Index: /data/empty.xml
===================================================================
--- /data/empty.xml	(revision 49)
+++ /data/empty.xml	(revision 49)
@@ -0,0 +1,3 @@
+<?xml version="1.0" encoding="UTF-8"?>
+<osm />
+
Index: /src/org/openstreetmap/josm/actions/SaveAction.java
===================================================================
--- /src/org/openstreetmap/josm/actions/SaveAction.java	(revision 48)
+++ /src/org/openstreetmap/josm/actions/SaveAction.java	(revision 49)
@@ -54,5 +54,5 @@
 			FileWriter fileWriter;
 			if (fn.endsWith(".gpx"))
-				new GpxWriter(fileWriter = new FileWriter(file)).output();
+				new GpxWriter(fileWriter = new FileWriter(file), Main.main.ds).output();
 			else if (fn.endsWith(".xml") || fn.endsWith(".osm"))
 				new OsmWriter(fileWriter = new FileWriter(file), Main.main.ds).output();
Index: /src/org/openstreetmap/josm/io/GpxReader.java
===================================================================
--- /src/org/openstreetmap/josm/io/GpxReader.java	(revision 48)
+++ /src/org/openstreetmap/josm/io/GpxReader.java	(revision 49)
@@ -2,6 +2,6 @@
 
 import static org.openstreetmap.josm.io.GpxWriter.GPX;
+import static org.openstreetmap.josm.io.GpxWriter.JOSM;
 import static org.openstreetmap.josm.io.GpxWriter.OSM;
-import static org.openstreetmap.josm.io.GpxWriter.JOSM;
 
 import java.io.IOException;
@@ -33,4 +33,13 @@
 	 */
 	public Reader source;
+	/**
+	 * Mapper to find new created objects that occoure more than once.
+	 */
+	private HashMap<Long, OsmPrimitive> newCreatedPrimitives = new HashMap<Long, OsmPrimitive>();
+	/**
+	 * Either set to true or false, depending whether the JOSM namespace declaration 
+	 * was found.
+	 */
+	private boolean mergeNodes = false;
 
 	/**
@@ -49,4 +58,5 @@
 			final SAXBuilder builder = new SAXBuilder();
 			Element root = builder.build(source).getRootElement();
+			mergeNodes = !root.getAdditionalNamespaces().contains(JOSM);
 			return parseDataSet(root);
 		} catch (NullPointerException npe) {
@@ -78,4 +88,5 @@
 				parseKeyValueTag(data, child);
 		}
+		data = (Node)getNewIfSeenBefore(data);
 		return data;
 	}
@@ -89,11 +100,18 @@
 		DataSet data = new DataSet();
 		// read waypoints not contained in tracks or areas
-		for (Object o : e.getChildren("wpt", GPX))
-			addNode(data, parseWaypoint((Element)o));
+		for (Object o : e.getChildren("wpt", GPX)) {
+			Node node = parseWaypoint((Element)o);
+			addNode(data, node);
+		}
 	
 		// read tracks (and line segments)
 		for (Object trackElement : e.getChildren("trk", GPX))
 			parseTrack((Element)trackElement, data);
-	
+
+		// reset new created ids to zero
+		for (OsmPrimitive osm : data.allPrimitives())
+			if (osm.id < 0)
+				osm.id = 0;
+		
 		return data;
 	}
@@ -116,6 +134,5 @@
 				Node start = null;
 				for (Object w : child.getChildren("trkpt", GPX)) {
-					Node node = parseWaypoint((Element)w);
-					node = addNode(ds, node);
+					Node node = addNode(ds, parseWaypoint((Element)w));
 					if (start == null)
 						start = node;
@@ -123,4 +140,5 @@
 						LineSegment lineSegment = new LineSegment(start, node);
 						parseKeyValueExtensions(lineSegment, child.getChild("extensions", GPX));
+						lineSegment = (LineSegment)getNewIfSeenBefore(lineSegment);
 						track.segments.add(lineSegment);
 						start = node;
@@ -136,17 +154,14 @@
 				parseKeyValueTag(track, child);
 		}
+		track = (Track)getNewIfSeenBefore(track);
 		ds.lineSegments.addAll(track.segments);
 		if (!realLineSegment)
 			ds.tracks.add(track);
 	}
-	
 
 	/**
 	 * Adds the node to allNodes if it is not already listed. Does respect the
-	 * preference setting "mergeNodes". Return the node in the list that correspond
+	 * setting "mergeNodes". Return the node in the list that correspond
 	 * to the node in the list (either the new added or the old found).
-	 * 
-	 * If reading raw gps data, mergeNodes are always on (To save memory. You
-	 * can't edit raw gps nodes anyway.)
 	 * 
 	 * @param data The DataSet to add the node to.
@@ -155,9 +170,21 @@
 	 */
 	private Node addNode(DataSet data, Node node) {
-		for (Node n : data.nodes)
-			if (node.coor.equalsLatLon(n.coor))
-				return n;
+		if (mergeNodes)
+			for (Node n : data.nodes)
+				if (node.coor.equalsLatLon(n.coor))
+					return n;
 		data.nodes.add(node);
 		return node;
+	}
+	
+
+	/**
+	 * @return Either the parameter or an index from the newCreatedPrimitives map
+	 * 		with the id seen before.
+	 */
+	private OsmPrimitive getNewIfSeenBefore(OsmPrimitive osm) {
+		if (newCreatedPrimitives.containsKey(osm.id))
+			return newCreatedPrimitives.get(osm.id);
+		return osm;
 	}
 
@@ -189,4 +216,6 @@
 			if (idElement != null)
 				osm.id = Long.parseLong(idElement.getText());
+			if (osm.id < 0 && !newCreatedPrimitives.containsKey(osm.id))
+				newCreatedPrimitives.put(osm.id, osm);
 			osm.modified = e.getChild("modified", JOSM) != null;
 			osm.setDeleted(e.getChild("deleted", JOSM) != null);
Index: /src/org/openstreetmap/josm/io/GpxWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/GpxWriter.java	(revision 48)
+++ /src/org/openstreetmap/josm/io/GpxWriter.java	(revision 49)
@@ -3,4 +3,5 @@
 import java.io.IOException;
 import java.io.Writer;
+import java.util.Collection;
 import java.util.HashMap;
 import java.util.LinkedList;
@@ -14,5 +15,5 @@
 import org.jdom.output.Format;
 import org.jdom.output.XMLOutputter;
-import org.openstreetmap.josm.Main;
+import org.openstreetmap.josm.data.osm.DataSet;
 import org.openstreetmap.josm.data.osm.Key;
 import org.openstreetmap.josm.data.osm.LineSegment;
@@ -50,4 +51,19 @@
 	 */
 	private Writer out;
+	/**
+	 * The dataset beeing processed.
+	 */
+	private DataSet ds;
+	/**
+	 * Map all new primitives to the element which hold them. After inserting everything,
+	 * the writer sets ids to every element that was in the list and had more than one
+	 * element using it. 
+	 */
+	private HashMap<OsmPrimitive, Collection<Element>> usedNewPrimitives = new HashMap<OsmPrimitive, Collection<Element>>();
+	/**
+	 * The counter for new created objects used more than once.
+	 * Starting at -1 and goes down.
+	 */
+	private long newIdCounter = -1;
 	
 	/**
@@ -57,6 +73,7 @@
 	 * @param out The Writer to store the result data in.
 	 */
-	public GpxWriter(Writer out) {
+	public GpxWriter(Writer out, DataSet ds) {
 		this.out = out;
+		this.ds = ds;
 	}
 
@@ -86,10 +103,12 @@
 		e.setAttribute("creator", "JOSM");
 		// for getting all unreferenced waypoints in the wpt-list
-		LinkedList<Node> unrefNodes = new LinkedList<Node>(Main.main.ds.nodes);
+		LinkedList<Node> unrefNodes = new LinkedList<Node>(ds.nodes);
 		// for getting all unreferenced line segments
-		LinkedList<LineSegment> unrefLs = new LinkedList<LineSegment>(Main.main.ds.lineSegments);
+		LinkedList<LineSegment> unrefLs = new LinkedList<LineSegment>(ds.lineSegments);
 
 		// tracks
-		for (Track t : Main.main.ds.tracks) {
+		for (Track t : ds.tracks) {
+			if (t.isDeleted() && t.id == 0)
+				continue;
 			Element tElem = new Element("trk", GPX);
 			HashMap<Key, String> keys = null;
@@ -119,4 +138,6 @@
 		// encode pending line segments as tracks
 		for (LineSegment ls : unrefLs) {
+			if (ls.isDeleted() && ls.id == 0)
+				continue;
 			Element t = new Element("trk", GPX);
 			t.getChildren().add(parseLineSegment(ls));
@@ -130,6 +151,22 @@
 
 		// waypoints (missing nodes)
-		for (Node n : unrefNodes)
+		for (Node n : unrefNodes) {
+			if (n.isDeleted() && n.id == 0)
+				continue;
 			e.getChildren().add(parseWaypoint(n, "wpt"));
+		}
+
+		// link all ids used more than once
+		for (Entry<OsmPrimitive, Collection<Element>> entry : usedNewPrimitives.entrySet()) {
+			if (entry.getValue().size() > 1) {
+				long id = newIdCounter--;
+				for (Element element : entry.getValue()) {
+					Element ext = element.getChild("extensions", GPX);
+					if (ext == null)
+						element.getChildren().add(ext = new Element("extensions", GPX));
+					ext.getChildren().add(new Element("uid", JOSM).setText(""+id));
+				}
+			}
+		}
 
 		return e;
@@ -242,9 +279,5 @@
 	@SuppressWarnings("unchecked")
 	private void addPropertyExtensions(Element e, Map<Key, String> keys, OsmPrimitive osm) {
-		if ((keys == null || keys.isEmpty()) && osm.id == 0 && !osm.modified && !osm.isDeleted() && !osm.modifiedProperties)
-			return;
-		Element extensions = e.getChild("extensions", GPX);
-		if (extensions == null)
-			e.getChildren().add(extensions = new Element("extensions", GPX));
+		LinkedList<Element> extensions = new LinkedList<Element>();
 		if (keys != null && !keys.isEmpty()) {
 			for (Entry<Key, String> prop : keys.entrySet()) {
@@ -252,24 +285,39 @@
 				propElement.setAttribute("key", prop.getKey().name);
 				propElement.setAttribute("value", prop.getValue());
-				extensions.getChildren().add(propElement);
+				extensions.add(propElement);
 			}
 		}
+		
 		if (osm.id != 0) {
 			Element propElement = new Element("uid", JOSM);
 			propElement.setText(""+osm.id);
-			extensions.getChildren().add(propElement);
+			extensions.add(propElement);
+		} else {
+			Collection<Element> l = usedNewPrimitives.get(osm);
+			if (l == null)
+				l = new LinkedList<Element>();
+			l.add(e);
+			usedNewPrimitives.put(osm, l);
 		}
 		if (osm.modified) {
 			Element modElement = new Element("modified", JOSM);
-			extensions.getChildren().add(modElement);
+			extensions.add(modElement);
 		}
 		if (osm.isDeleted()) {
 			Element modElement = new Element("deleted", JOSM);
-			extensions.getChildren().add(modElement);
+			extensions.add(modElement);
 		}
 		if (osm.modifiedProperties) {
 			Element modElement = new Element("modifiedProperties", JOSM);
-			extensions.getChildren().add(modElement);
-		}
+			extensions.add(modElement);
+		}
+		
+		if (extensions.isEmpty())
+			return;
+
+		Element ext = e.getChild("extensions", GPX);
+		if (ext == null)
+			e.getChildren().add(ext = new Element("extensions", GPX));
+		ext.getChildren().addAll(extensions);
 	}
 }
Index: /src/org/openstreetmap/josm/io/OsmWriter.java
===================================================================
--- /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 48)
+++ /src/org/openstreetmap/josm/io/OsmWriter.java	(revision 49)
@@ -4,4 +4,5 @@
 import java.io.Writer;
 import java.util.Collection;
+import java.util.HashMap;
 import java.util.LinkedList;
 import java.util.List;
@@ -39,4 +40,9 @@
 	 */
 	private long newIdCounter = -1;
+	/**
+	 * All newly created ids and their primitive that uses it. This is a back reference
+	 * map to allow references to use the correnct primitives.
+	 */
+	private HashMap<OsmPrimitive, Long> usedNewIds = new HashMap<OsmPrimitive, Long>();
 
 	/**
@@ -72,5 +78,5 @@
 		Collection<Element> allDeleted = deleted.getChildren();
 		for (OsmPrimitive osm : ds.allPrimitives()) {
-			if (osm.isDeleted()) {
+			if (osm.isDeleted() && osm.id != 0) {
 				osm.visit(this);
 				allDeleted.add(element);
@@ -103,6 +109,8 @@
 	private void addProperties(Element e, OsmPrimitive osm) {
 		long id = osm.id;
-		if (id == 0)
+		if (id == 0) {
 			id = newIdCounter--;
+			usedNewIds.put(osm, id);
+		}
 		e.setAttribute("uid", ""+id);
 		if (osm.keys != null)
@@ -127,6 +135,13 @@
 		element = new Element("segment");
 		addProperties(element, ls);
-		element.setAttribute("from", ""+ls.start.id);
-		element.setAttribute("to", ""+ls.end.id);
+		element.setAttribute("from", ""+getUsedId(ls.start));
+		element.setAttribute("to", ""+getUsedId(ls.end));
+	}
+
+	/**
+	 * Return the id for the given osm primitive (may access the usedId map)
+	 */
+	private Long getUsedId(OsmPrimitive osm) {
+		return osm.id == 0 ? usedNewIds.get(osm) : osm.id;
 	}
 
@@ -139,5 +154,5 @@
 		addProperties(element, t);
 		for (LineSegment ls : t.segments)
-			element.getChildren().add(new Element("segment").setAttribute("uid", ""+ls.id));
+			element.getChildren().add(new Element("segment").setAttribute("uid", ""+getUsedId(ls)));
 	}
 
@@ -147,3 +162,2 @@
 	}
 }
-
Index: /test/org/openstreetmap/josm/test/GpxWriterTest.java
===================================================================
--- /test/org/openstreetmap/josm/test/GpxWriterTest.java	(revision 49)
+++ /test/org/openstreetmap/josm/test/GpxWriterTest.java	(revision 49)
@@ -0,0 +1,85 @@
+package org.openstreetmap.josm.test;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+
+import junit.framework.TestCase;
+
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.Namespace;
+import org.jdom.input.SAXBuilder;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.io.GpxWriter;
+import org.openstreetmap.josm.test.framework.Bug;
+import org.openstreetmap.josm.test.framework.DataSetTestCaseHelper;
+
+public class GpxWriterTest extends TestCase {
+
+	private static Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
+	private static Namespace JOSM = Namespace.getNamespace("http://wiki.eigenheimstrasse.de/wiki/JOSM");
+
+	private DataSet ds;
+
+	private Element root;
+
+	/**
+	 * Verify that deleted objects that are not uploaded to the server does not show up
+	 * in gpx save output at all.
+	 */
+	@Bug(47)
+	public void testDeleteNewDoesReallyRemove() throws JDOMException, IOException {
+		ds.tracks.iterator().next().setDeleted(true);
+		root = reparse();
+		assertEquals("track has vanished and 3 trk (segments) left", 3, root.getChildren("trk", GPX).size());
+	}
+
+	
+	/**
+	 * Verify, that new created elements, if and only if they occoure more than once in
+	 * the file, have a negative id attached.
+	 */
+	@Bug(47)
+	public void testNewCreateAddIdWhenMoreThanOnce() {
+		// the trk with the two trkseg's only occoure once -> no extension id
+		Element realTrack = null;
+		for (Object o : root.getChildren("trk", GPX)) {
+			Element e = (Element)o;
+			if (e.getChildren("trkseg", GPX).size() != 2)
+				continue;
+			Element ext = e.getChild("extensions", GPX);
+			if (ext != null)
+				assertEquals("no id for track (used only once)", 0, ext.getChildren("uid", JOSM).size());
+			realTrack = e;
+		}
+		assertNotNull("track not found in GPX file", realTrack);
+		
+		// the second point of the first segment of the tracks has an id
+		Element trkseg = (Element)realTrack.getChildren("trkseg", GPX).get(0);
+		Element trkpt = (Element)trkseg.getChildren("trkpt", GPX).get(1);
+		assertEquals("trackpoint used twice but has no extensions at all", 1, trkpt.getChildren("extensions", GPX).size());
+		Element ext = trkpt.getChild("extensions", GPX);
+		assertEquals("trackpoint used twice but has no id", 1, ext.getChildren("uid", JOSM).size());
+	}
+
+
+	/**
+	 * Parse the intern dataset and return the root gpx - element.
+	 */
+	private Element reparse() throws IOException, JDOMException {
+		StringWriter out = new StringWriter();
+		GpxWriter writer = new GpxWriter(out, ds);
+		writer.output();
+		Element root = new SAXBuilder().build(new StringReader(out.toString())).getRootElement();
+		return root;
+	}
+
+
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		ds = DataSetTestCaseHelper.createCommon();
+		root = reparse();
+	}
+}
Index: /test/org/openstreetmap/josm/test/OsmWriterTest.java
===================================================================
--- /test/org/openstreetmap/josm/test/OsmWriterTest.java	(revision 49)
+++ /test/org/openstreetmap/josm/test/OsmWriterTest.java	(revision 49)
@@ -0,0 +1,117 @@
+package org.openstreetmap.josm.test;
+
+import java.io.IOException;
+import java.io.StringReader;
+import java.io.StringWriter;
+import java.util.HashSet;
+import java.util.List;
+import java.util.Set;
+
+import junit.framework.TestCase;
+
+import org.jdom.Element;
+import org.jdom.JDOMException;
+import org.jdom.input.SAXBuilder;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.io.OsmWriter;
+import org.openstreetmap.josm.test.framework.Bug;
+import org.openstreetmap.josm.test.framework.DataSetTestCaseHelper;
+
+/**
+ * Test various problems with generation of OSM-XML
+ * @author Imi
+ */
+public class OsmWriterTest extends TestCase {
+
+	private DataSet ds;
+	private Element osm;
+	private List<Element> nodes;
+	private List<Element> lineSegments;
+	private List<Element> tracks;
+	private List<Element> deleted;
+	
+	/**
+	 * Test that the id generation creates unique ids and all are negative
+	 */
+	@SuppressWarnings("unchecked")
+	public void testIDGenerationUniqueNegative() {
+		Set<Long> ids = new HashSet<Long>();
+		for (Element e : (List<Element>)osm.getChildren()) {
+			long id = Long.parseLong(e.getAttributeValue("uid"));
+			assertTrue("id "+id+" is negative", id < 0);
+			ids.add(id);
+		}
+		assertEquals(nodes.size()+lineSegments.size()+tracks.size(), ids.size());
+	}
+
+	/**
+	 * Verify that generated ids of higher level primitives point to the 
+	 * generated lower level ids (tracks point to segments which point to nodes).
+	 */
+	@Bug(47)
+	public void testIDGenerationReferences() {
+		long id1 = Long.parseLong(getAttr(osm, "node", 0, "uid"));
+		long id2 = Long.parseLong(getAttr(osm, "node", 1, "uid"));
+		long lsFrom = Long.parseLong(getAttr(osm, "segment", 0, "from"));
+		long lsTo = Long.parseLong(getAttr(osm, "segment", 0, "to"));
+		assertEquals(id1, lsFrom);
+		assertEquals(id2, lsTo);
+		assertEquals(id2, lsTo);
+
+		long ls1 = Long.parseLong(getAttr(osm, "segment", 0, "uid"));
+		long ls2 = Long.parseLong(getAttr(osm, "segment", 1, "uid"));
+		long t1 = Long.parseLong(getAttr(osm.getChild("track"), "segment", 0, "uid"));
+		long t2 = Long.parseLong(getAttr(osm.getChild("track"), "segment", 1, "uid"));
+		assertEquals(ls1, t1);
+		assertEquals(ls2, t2);
+	}
+
+	/**
+	 * Verify that deleted objects that are not uploaded to the server does not show up
+	 * in xml save output at all.
+	 */
+	@Bug(47)
+	public void testDeleteNewDoesReallyRemove() throws IOException, JDOMException {
+		ds.tracks.iterator().next().setDeleted(true);
+		reparse();
+		assertEquals(0, deleted.size());
+	}
+
+	
+	
+	
+	
+	@Override
+	protected void setUp() throws Exception {
+		super.setUp();
+		// create some data
+		ds = DataSetTestCaseHelper.createCommon();
+		reparse();
+	}
+
+	/**
+	 * Get an attribute out of an object of the root element.
+	 */
+	private String getAttr(Element root, String objName, int objPos, String attrName) {
+		Element e = (Element)root.getChildren(objName).get(objPos);
+		return e.getAttributeValue(attrName);
+	}
+
+	/**
+	 * Reparse the dataset into the lists members..
+	 */
+	@SuppressWarnings("unchecked")
+	private void reparse() throws IOException, JDOMException {
+		StringWriter out = new StringWriter();
+
+		OsmWriter osmWriter = new OsmWriter(out, ds);
+		osmWriter.output();
+		
+		// reparse
+		osm = new SAXBuilder().build(new StringReader(out.toString())).getRootElement();
+		nodes = osm.getChildren("node");
+		lineSegments = osm.getChildren("segment");
+		tracks = osm.getChildren("track");
+		deleted = osm.getChildren("deleted");
+	}
+}
Index: /test/org/openstreetmap/josm/test/framework/Bug.java
===================================================================
--- /test/org/openstreetmap/josm/test/framework/Bug.java	(revision 49)
+++ /test/org/openstreetmap/josm/test/framework/Bug.java	(revision 49)
@@ -0,0 +1,13 @@
+package org.openstreetmap.josm.test.framework;
+
+/**
+ * Annotation that indicate that a specific test case function was a bug.
+ * @author Imi
+ */
+public @interface Bug {
+	/**
+	 * The revision this bug was detected. (Can be later than the actual first occourence.
+	 * This number is just to have a revision where the bug actually happen.)
+	 */
+	int value();
+}
Index: /test/org/openstreetmap/josm/test/framework/DataSetTestCaseHelper.java
===================================================================
--- /test/org/openstreetmap/josm/test/framework/DataSetTestCaseHelper.java	(revision 49)
+++ /test/org/openstreetmap/josm/test/framework/DataSetTestCaseHelper.java	(revision 49)
@@ -0,0 +1,61 @@
+package org.openstreetmap.josm.test.framework;
+
+import org.openstreetmap.josm.data.GeoPoint;
+import org.openstreetmap.josm.data.osm.DataSet;
+import org.openstreetmap.josm.data.osm.LineSegment;
+import org.openstreetmap.josm.data.osm.Node;
+import org.openstreetmap.josm.data.osm.Track;
+
+
+/**
+ * Test cases that need to manupulate a data set can use this helper.
+ *  
+ * @author Imi
+ */
+public class DataSetTestCaseHelper {
+
+	/**
+	 * Create a common dataset consisting of:
+	 * - 5 random nodes
+	 * - ls between node 0 and 1
+	 * - ls between node 1 and 2
+	 * - ls between node 3 and 4
+	 * - a track with ls 0 and 1
+	 */
+	public static DataSet createCommon() {
+		DataSet ds = new DataSet();
+		Node n1 = createNode(ds);
+		Node n2 = createNode(ds);
+		Node n3 = createNode(ds);
+		Node n4 = createNode(ds);
+		Node n5 = createNode(ds);
+		LineSegment ls1 = createLineSegment(ds, n1, n2);
+		LineSegment ls2 = createLineSegment(ds, n2, n3);
+		createLineSegment(ds, n4, n5);
+		Track t = new Track();
+		t.segments.add(ls1);
+		t.segments.add(ls2);
+		ds.tracks.add(t);
+		return ds;
+	}
+	
+	/**
+	 * Create a line segment with out of the given nodes.
+	 */
+	private static LineSegment createLineSegment(DataSet ds, Node n1, Node n2) {
+		LineSegment ls = new LineSegment(n1, n2);
+		ds.lineSegments.add(ls);
+		return ls;
+	}
+
+	/**
+	 * Add a random node.
+	 */
+	private static Node createNode(DataSet ds) {
+		Node node = new Node();
+		node.coor = new GeoPoint(Math.random(), Math.random());
+		ds.nodes.add(node);
+		return node;
+	}
+
+}
