001 // License: GPL. Copyright 2007 by Immanuel Scholz and others 002 package org.openstreetmap.josm.io; 003 004 import static org.openstreetmap.josm.tools.I18n.tr; 005 006 import java.io.BufferedWriter; 007 import java.io.OutputStream; 008 import java.io.OutputStreamWriter; 009 import java.io.PrintWriter; 010 import java.io.UnsupportedEncodingException; 011 import java.util.Arrays; 012 import java.util.Collection; 013 import java.util.List; 014 import java.util.Map; 015 016 import org.openstreetmap.josm.data.Bounds; 017 import org.openstreetmap.josm.data.coor.LatLon; 018 import org.openstreetmap.josm.data.gpx.GpxData; 019 import org.openstreetmap.josm.data.gpx.GpxLink; 020 import org.openstreetmap.josm.data.gpx.GpxRoute; 021 import org.openstreetmap.josm.data.gpx.GpxTrack; 022 import org.openstreetmap.josm.data.gpx.GpxTrackSegment; 023 import org.openstreetmap.josm.data.gpx.WayPoint; 024 025 /** 026 * Writes GPX files from GPX data or OSM data. 027 */ 028 public class GpxWriter extends XmlWriter { 029 030 public GpxWriter(PrintWriter out) { 031 super(out); 032 } 033 034 public GpxWriter(OutputStream out) throws UnsupportedEncodingException { 035 super(new PrintWriter(new BufferedWriter(new OutputStreamWriter(out, "UTF-8")))); 036 } 037 038 public GpxWriter() { 039 super(null); 040 //sorry for this one here, this will be cleaned up once the new scheme works 041 } 042 043 private GpxData data; 044 private String indent = ""; 045 046 private final static int WAY_POINT = 0; 047 private final static int ROUTE_POINT = 1; 048 private final static int TRACK_POINT = 2; 049 050 public void write(GpxData data) { 051 this.data = data; 052 out.println("<?xml version='1.0' encoding='UTF-8'?>"); 053 out.println("<gpx version=\"1.1\" creator=\"JOSM GPX export\" xmlns=\"http://www.topografix.com/GPX/1/1\"\n" + 054 " xmlns:xsi=\"http://www.w3.org/2001/XMLSchema-instance\" \n" + 055 " xsi:schemaLocation=\"http://www.topografix.com/GPX/1/1 http://www.topografix.com/GPX/1/1/gpx.xsd\">"); 056 indent = " "; 057 writeMetaData(); 058 writeWayPoints(); 059 writeRoutes(); 060 writeTracks(); 061 out.print("</gpx>"); 062 out.flush(); 063 } 064 065 public static List<String> WPT_KEYS = Arrays.asList("ele", "time", "magvar", "geoidheight", 066 "name", "cmt", "desc", "src", GpxData.META_LINKS, "sym", "number", "type", 067 "fix", "sat", "hdop", "vdop", "pdop", "ageofdgpsdata", "dgpsid"); 068 @SuppressWarnings("unchecked") 069 private void writeAttr(Map<String, Object> attr) { 070 for (String key : WPT_KEYS) { 071 Object value = attr.get(key); 072 if (value != null) { 073 if (key.equals(GpxData.META_LINKS)) { 074 for (GpxLink link : (Collection<GpxLink>) value) { 075 gpxLink(link); 076 } 077 } else { 078 simpleTag(key, value.toString()); 079 } 080 } 081 } 082 } 083 084 @SuppressWarnings("unchecked") 085 private void writeMetaData() { 086 Map<String, Object> attr = data.attr; 087 openln("metadata"); 088 089 // write the description 090 if (attr.containsKey(GpxData.META_DESC)) { 091 simpleTag("desc", (String)attr.get(GpxData.META_DESC)); 092 } 093 094 // write the author details 095 if (attr.containsKey(GpxData.META_AUTHOR_NAME) 096 || attr.containsKey(GpxData.META_AUTHOR_EMAIL)) { 097 openln("author"); 098 // write the name 099 simpleTag("name", (String) attr.get(GpxData.META_AUTHOR_NAME)); 100 // write the email address 101 if(attr.containsKey(GpxData.META_AUTHOR_EMAIL)) { 102 String[] tmp = ((String)attr.get(GpxData.META_AUTHOR_EMAIL)).split("@"); 103 if(tmp.length == 2) { 104 inline("email", "id=\"" + tmp[0] + "\" domain=\""+tmp[1]+"\""); 105 } 106 } 107 // write the author link 108 gpxLink((GpxLink) attr.get(GpxData.META_AUTHOR_LINK)); 109 closeln("author"); 110 } 111 112 // write the copyright details 113 if(attr.containsKey(GpxData.META_COPYRIGHT_LICENSE) 114 || attr.containsKey(GpxData.META_COPYRIGHT_YEAR)) { 115 openAtt("copyright", "author=\""+ attr.get(GpxData.META_COPYRIGHT_AUTHOR) +"\""); 116 if(attr.containsKey(GpxData.META_COPYRIGHT_YEAR)) { 117 simpleTag("year", (String) attr.get(GpxData.META_COPYRIGHT_YEAR)); 118 } 119 if(attr.containsKey(GpxData.META_COPYRIGHT_LICENSE)) { 120 simpleTag("license", encode((String) attr.get(GpxData.META_COPYRIGHT_LICENSE))); 121 } 122 closeln("copyright"); 123 } 124 125 // write links 126 if(attr.containsKey(GpxData.META_LINKS)) { 127 for (GpxLink link : (Collection<GpxLink>) attr.get(GpxData.META_LINKS)) { 128 gpxLink(link); 129 } 130 } 131 132 // write keywords 133 if (attr.containsKey(GpxData.META_KEYWORDS)) { 134 simpleTag("keywords", (String)attr.get(GpxData.META_KEYWORDS)); 135 } 136 137 Bounds bounds = data.recalculateBounds(); 138 if(bounds != null) 139 { 140 String b = "minlat=\"" + bounds.getMin().lat() + "\" minlon=\"" + bounds.getMin().lon() + 141 "\" maxlat=\"" + bounds.getMax().lat() + "\" maxlon=\"" + bounds.getMax().lon() + "\"" ; 142 inline("bounds", b); 143 } 144 145 closeln("metadata"); 146 } 147 148 private void writeWayPoints() { 149 for (WayPoint pnt : data.waypoints) { 150 wayPoint(pnt, WAY_POINT); 151 } 152 } 153 154 private void writeRoutes() { 155 for (GpxRoute rte : data.routes) { 156 openln("rte"); 157 writeAttr(rte.attr); 158 for (WayPoint pnt : rte.routePoints) { 159 wayPoint(pnt, ROUTE_POINT); 160 } 161 closeln("rte"); 162 } 163 } 164 165 private void writeTracks() { 166 for (GpxTrack trk : data.tracks) { 167 openln("trk"); 168 writeAttr(trk.getAttributes()); 169 for (GpxTrackSegment seg : trk.getSegments()) { 170 openln("trkseg"); 171 for (WayPoint pnt : seg.getWayPoints()) { 172 wayPoint(pnt, TRACK_POINT); 173 } 174 closeln("trkseg"); 175 } 176 closeln("trk"); 177 } 178 } 179 180 private void openln(String tag) { 181 open(tag); 182 out.println(); 183 } 184 185 private void open(String tag) { 186 out.print(indent + "<" + tag + ">"); 187 indent += " "; 188 } 189 190 private void openAtt(String tag, String attributes) { 191 out.println(indent + "<" + tag + " " + attributes + ">"); 192 indent += " "; 193 } 194 195 private void inline(String tag, String attributes) { 196 out.println(indent + "<" + tag + " " + attributes + "/>"); 197 } 198 199 private void close(String tag) { 200 indent = indent.substring(2); 201 out.print(indent + "</" + tag + ">"); 202 } 203 204 private void closeln(String tag) { 205 close(tag); 206 out.println(); 207 } 208 209 /** 210 * if content not null, open tag, write encoded content, and close tag 211 * else do nothing. 212 */ 213 private void simpleTag(String tag, String content) { 214 if (content != null && content.length() > 0) { 215 open(tag); 216 out.print(encode(content)); 217 out.println("</" + tag + ">"); 218 indent = indent.substring(2); 219 } 220 } 221 222 /** 223 * output link 224 */ 225 private void gpxLink(GpxLink link) { 226 if (link != null) { 227 openAtt("link", "href=\"" + link.uri + "\""); 228 simpleTag("text", link.text); 229 simpleTag("type", link.type); 230 closeln("link"); 231 } 232 } 233 234 /** 235 * output a point 236 */ 237 private void wayPoint(WayPoint pnt, int mode) { 238 String type; 239 switch(mode) { 240 case WAY_POINT: 241 type = "wpt"; 242 break; 243 case ROUTE_POINT: 244 type = "rtept"; 245 break; 246 case TRACK_POINT: 247 type = "trkpt"; 248 break; 249 default: 250 throw new RuntimeException(tr("Unknown mode {0}.", mode)); 251 } 252 if (pnt != null) { 253 LatLon c = pnt.getCoor(); 254 String coordAttr = "lat=\"" + c.lat() + "\" lon=\"" + c.lon() + "\""; 255 if (pnt.attr.isEmpty()) { 256 inline(type, coordAttr); 257 } else { 258 openAtt(type, coordAttr); 259 writeAttr(pnt.attr); 260 closeln(type); 261 } 262 } 263 } 264 }