source: josm/src/org/openstreetmap/josm/io/GpxWriter.java@ 40

Last change on this file since 40 was 35, checked in by imi, 18 years ago
  • fixed bug in UTM
  • upload of nodes and segments
  • fixed bugs in display the selection
File size: 8.7 KB
Line 
1package org.openstreetmap.josm.io;
2
3import java.io.IOException;
4import java.io.Writer;
5import java.util.HashMap;
6import java.util.LinkedList;
7import java.util.Map;
8import java.util.StringTokenizer;
9import java.util.Map.Entry;
10
11import org.jdom.Document;
12import org.jdom.Element;
13import org.jdom.Namespace;
14import org.jdom.output.Format;
15import org.jdom.output.XMLOutputter;
16import org.openstreetmap.josm.Main;
17import org.openstreetmap.josm.data.osm.Key;
18import org.openstreetmap.josm.data.osm.LineSegment;
19import org.openstreetmap.josm.data.osm.Node;
20import org.openstreetmap.josm.data.osm.OsmPrimitive;
21import org.openstreetmap.josm.data.osm.Track;
22
23/**
24 * Exports a dataset to GPX data. All information available are tried to store in
25 * the gpx. If no corresponding tag is available in GPX, use
26 * <code>&lt;extensions&gt;</code> instead.
27 *
28 * GPX-Track segments are stored as 2-node-pairs, so no &lt;trkseg&gt; with more
29 * or less than 2 &lt;trkpt&gt; are exported.
30 *
31 * @author imi
32 */
33public class GpxWriter {
34
35 /**
36 * The GPX namespace used.
37 */
38 public static final Namespace GPX = Namespace.getNamespace("http://www.topografix.com/GPX/1/0");
39 /**
40 * The OSM namespace used (for extensions).
41 */
42 public static final Namespace OSM = Namespace.getNamespace("osm", "http://www.openstreetmap.org");
43 /**
44 * The JOSM namespace (for JOSM-extensions).
45 */
46 public static final Namespace JOSM = Namespace.getNamespace("josm", "http://wiki.eigenheimstrasse.de/wiki/JOSM");
47
48 /**
49 * This is the output writer to store the resulting data in.
50 */
51 private Writer out;
52
53 /**
54 * Create a GpxWrite from an output writer. As example to write in a file,
55 * use FileWriter.
56 *
57 * @param out The Writer to store the result data in.
58 */
59 public GpxWriter(Writer out) {
60 this.out = out;
61 }
62
63
64 /**
65 * Do the output in the former set writer.
66 * @exception IOException In case of IO errors, throw this exception.
67 */
68 public void output() throws IOException {
69 Element root = parseDataSet();
70 root.addNamespaceDeclaration(OSM);
71 root.addNamespaceDeclaration(JOSM);
72 Document d = new Document(root);
73 XMLOutputter xmlOut = new XMLOutputter(Format.getPrettyFormat());
74 xmlOut.output(d, out);
75 }
76
77
78 /**
79 * Write the whole DataSet in an JDom-Element and return the new element.
80 * @return The created element, out of the dataset.
81 */
82 @SuppressWarnings("unchecked")
83 private Element parseDataSet() {
84 Element e = new Element("gpx", GPX);
85 e.setAttribute("version", "1.0");
86 e.setAttribute("creator", "JOSM");
87 // for getting all unreferenced waypoints in the wpt-list
88 LinkedList<Node> unrefNodes = new LinkedList<Node>(Main.main.ds.nodes);
89 // for getting all unreferenced line segments
90 LinkedList<LineSegment> unrefLs = new LinkedList<LineSegment>(Main.main.ds.lineSegments);
91
92 // tracks
93 for (Track t : Main.main.ds.tracks) {
94 Element tElem = new Element("trk", GPX);
95 HashMap<Key, String> keys = null;
96 if (t.keys != null) {
97 keys = new HashMap<Key, String>(t.keys);
98 addAndRemovePropertyTag("name", tElem, keys);
99 addAndRemovePropertyTag("cmt", tElem, keys);
100 addAndRemovePropertyTag("desc", tElem, keys);
101 addAndRemovePropertyTag("src", tElem, keys);
102 addAndRemovePropertyLinkTag(tElem, keys);
103 addAndRemovePropertyTag("number", tElem, keys);
104 addAndRemovePropertyTag("type", tElem, keys);
105 }
106 addPropertyExtensions(tElem, keys, t);
107
108 // line segments
109 for (LineSegment ls : t.segments) {
110 tElem.getChildren().add(parseLineSegment(ls));
111 unrefNodes.remove(ls.start);
112 unrefNodes.remove(ls.end);
113 unrefLs.remove(ls);
114 }
115
116 e.getChildren().add(tElem);
117 }
118
119 // encode pending line segments as tracks
120 for (LineSegment ls : unrefLs) {
121 Element t = new Element("trk", GPX);
122 t.getChildren().add(parseLineSegment(ls));
123 unrefNodes.remove(ls.start);
124 unrefNodes.remove(ls.end);
125 Element ext = new Element("extensions", GPX);
126 ext.getChildren().add(new Element("segment", JOSM));
127 t.getChildren().add(ext);
128 e.getChildren().add(t);
129 }
130
131 // waypoints (missing nodes)
132 for (Node n : unrefNodes)
133 e.getChildren().add(parseWaypoint(n, "wpt"));
134
135 return e;
136 }
137
138
139 /**
140 * Parse a line segment and store it into a JDOM-Element. Return that element.
141 */
142 @SuppressWarnings("unchecked")
143 private Element parseLineSegment(LineSegment ls) {
144 Element lsElem = new Element("trkseg", GPX);
145 addPropertyExtensions(lsElem, ls.keys, ls);
146 lsElem.getChildren().add(parseWaypoint(ls.start, "trkpt"));
147 lsElem.getChildren().add(parseWaypoint(ls.end, "trkpt"));
148 return lsElem;
149 }
150
151 /**
152 * Parse a waypoint (node) and store it into an JDOM-Element. Return that
153 * element.
154 *
155 * @param n The Node to parse and store
156 * @param name The name of the tag (different names for nodes in GPX)
157 * @return The resulting GPX-Element
158 */
159 private Element parseWaypoint(Node n, String name) {
160 Element e = new Element(name, GPX);
161 e.setAttribute("lat", Double.toString(n.coor.lat));
162 e.setAttribute("lon", Double.toString(n.coor.lon));
163 HashMap<Key, String> keys = null;
164 if (n.keys != null) {
165 keys = new HashMap<Key, String>(n.keys);
166 addAndRemovePropertyTag("ele", e, keys);
167 addAndRemovePropertyTag("time", e, keys);
168 addAndRemovePropertyTag("magvar", e, keys);
169 addAndRemovePropertyTag("geoidheight", e, keys);
170 addAndRemovePropertyTag("name", e, keys);
171 addAndRemovePropertyTag("cmt", e, keys);
172 addAndRemovePropertyTag("desc", e, keys);
173 addAndRemovePropertyTag("src", e, keys);
174 addAndRemovePropertyLinkTag(e, keys);
175 addAndRemovePropertyTag("sym", e, keys);
176 addAndRemovePropertyTag("type", e, keys);
177 addAndRemovePropertyTag("fix", e, keys);
178 addAndRemovePropertyTag("sat", e, keys);
179 addAndRemovePropertyTag("hdop", e, keys);
180 addAndRemovePropertyTag("vdop", e, keys);
181 addAndRemovePropertyTag("pdop", e, keys);
182 addAndRemovePropertyTag("ageofdgpsdata", e, keys);
183 addAndRemovePropertyTag("dgpsid", e, keys);
184 }
185 addPropertyExtensions(e, keys, n);
186 return e;
187 }
188
189
190 /**
191 * Add a link-tag to the element, if the property list contain a value named
192 * "link". The property is removed from the map afterwards.
193 *
194 * For the format, @see GpxReader#parseKeyValueLink(OsmPrimitive, Element).
195 * @param e The element to add the link to.
196 * @param keys The map containing the link property.
197 */
198 @SuppressWarnings("unchecked")
199 private void addAndRemovePropertyLinkTag(Element e, Map<Key, String> keys) {
200 Key key = Key.get("link");
201 String value = keys.get(key);
202 if (value != null) {
203 StringTokenizer st = new StringTokenizer(value, ";");
204 if (st.countTokens() != 2)
205 return;
206 Element link = new Element("link", GPX);
207 link.getChildren().add(new Element("type", GPX).setText(st.nextToken()));
208 link.getChildren().add(0,new Element("text", GPX).setText(st.nextToken()));
209 e.getChildren().add(link);
210 keys.remove(key);
211 }
212 }
213
214
215 /**
216 * Helper to add a property with a given name as tag to the element. This
217 * will look like &lt;name&gt;<i>keys.get(name)</i>&lt;/name&gt;
218 *
219 * After adding, the property is removed from the map.
220 *
221 * If the property does not exist, nothing is done.
222 *
223 * @param name The properties name
224 * @param e The element to add the tag to.
225 * @param osm The data to get the property from.
226 */
227 @SuppressWarnings("unchecked")
228 private void addAndRemovePropertyTag(String name, Element e, Map<Key, String> keys) {
229 Key key = Key.get(name);
230 String value = keys.get(key);
231 if (value != null) {
232 e.getChildren().add(new Element(name, GPX).setText(value));
233 keys.remove(key);
234 }
235 }
236
237 /**
238 * Add the property in the entry as &lt;extensions&gt; to the element
239 * @param e The element to add the property to.
240 * @param prop The property to add.
241 */
242 @SuppressWarnings("unchecked")
243 private void addPropertyExtensions(Element e, Map<Key, String> keys, OsmPrimitive osm) {
244 if ((keys == null || keys.isEmpty()) && osm.id == 0 && !osm.modified && !osm.modifiedProperties)
245 return;
246 Element extensions = e.getChild("extensions", GPX);
247 if (extensions == null)
248 e.getChildren().add(extensions = new Element("extensions", GPX));
249 if (keys != null && !keys.isEmpty()) {
250 for (Entry<Key, String> prop : keys.entrySet()) {
251 Element propElement = new Element("property", OSM);
252 propElement.setAttribute("key", prop.getKey().name);
253 propElement.setAttribute("value", prop.getValue());
254 extensions.getChildren().add(propElement);
255 }
256 }
257 if (osm.id != 0) {
258 Element propElement = new Element("uid", JOSM);
259 propElement.setText(""+osm.id);
260 extensions.getChildren().add(propElement);
261 }
262 if (osm.modified) {
263 Element modElement = new Element("modified", JOSM);
264 extensions.getChildren().add(modElement);
265 }
266 if (osm.modifiedProperties) {
267 Element modElement = new Element("modifiedProperties", JOSM);
268 extensions.getChildren().add(modElement);
269 }
270 }
271}
Note: See TracBrowser for help on using the repository browser.