1 | package org.openstreetmap.josm.io;
|
---|
2 |
|
---|
3 | import static org.openstreetmap.josm.tools.I18n.tr;
|
---|
4 |
|
---|
5 | import java.io.File;
|
---|
6 | import java.io.IOException;
|
---|
7 | import java.io.InputStream;
|
---|
8 | import java.io.InputStreamReader;
|
---|
9 | import java.util.ArrayList;
|
---|
10 | import java.util.Collection;
|
---|
11 | import java.util.HashMap;
|
---|
12 | import java.util.LinkedList;
|
---|
13 | import java.util.Stack;
|
---|
14 |
|
---|
15 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
16 | import org.openstreetmap.josm.gui.layer.RawGpsLayer.GpsPoint;
|
---|
17 | import org.openstreetmap.josm.gui.layer.markerlayer.Marker;
|
---|
18 | import org.openstreetmap.josm.gui.layer.markerlayer.MarkerProducers;
|
---|
19 | import org.xml.sax.Attributes;
|
---|
20 | import org.xml.sax.SAXException;
|
---|
21 |
|
---|
22 | import uk.co.wilson.xml.MinML2;
|
---|
23 |
|
---|
24 | /**
|
---|
25 | * Read raw gps data from a gpx file. Only way points with their ways segments
|
---|
26 | * and waypoints are imported.
|
---|
27 | * @author imi
|
---|
28 | */
|
---|
29 | public class RawGpsReader {
|
---|
30 |
|
---|
31 | /**
|
---|
32 | * The relative path when constructing markers from wpt-tags. Passed to
|
---|
33 | * {@link MarkerProducers#createMarker(LatLon, java.util.Map, String)}
|
---|
34 | */
|
---|
35 | private File relativeMarkerPath;
|
---|
36 |
|
---|
37 | /**
|
---|
38 | * Hold the resulting gps data (tracks and their track points)
|
---|
39 | */
|
---|
40 | public Collection<Collection<GpsPoint>> trackData = new LinkedList<Collection<GpsPoint>>();
|
---|
41 |
|
---|
42 | /**
|
---|
43 | * Hold the waypoints of the gps data.
|
---|
44 | */
|
---|
45 | public Collection<Marker> markerData = new ArrayList<Marker>();
|
---|
46 |
|
---|
47 | private class Parser extends MinML2 {
|
---|
48 | /**
|
---|
49 | * Current track to be read. The last entry is the current trkpt.
|
---|
50 | * If in wpt-mode, it contain only one GpsPoint.
|
---|
51 | */
|
---|
52 | private Collection<GpsPoint> current = new LinkedList<GpsPoint>();
|
---|
53 | private LatLon currentLatLon;
|
---|
54 | private HashMap<String, String> currentTagValues = new HashMap<String, String>();
|
---|
55 | private Stack<String> tags = new Stack<String>();
|
---|
56 |
|
---|
57 | @Override public void startElement(String namespaceURI, String localName, String qName, Attributes atts) throws SAXException {
|
---|
58 | if (qName.equals("wpt") || qName.equals("trkpt")) {
|
---|
59 | try {
|
---|
60 | double lat = Double.parseDouble(atts.getValue("lat"));
|
---|
61 | double lon = Double.parseDouble(atts.getValue("lon"));
|
---|
62 | if (Math.abs(lat) > 90)
|
---|
63 | throw new SAXException(tr("Data error: lat value \"{0}\" is out of bounds.", lat));
|
---|
64 | if (Math.abs(lon) > 180)
|
---|
65 | throw new SAXException(tr("Data error: lon value \"{0}\" is out of bounds.", lon));
|
---|
66 | currentLatLon = new LatLon(lat, lon);
|
---|
67 | } catch (NumberFormatException e) {
|
---|
68 | e.printStackTrace();
|
---|
69 | throw new SAXException(e);
|
---|
70 | }
|
---|
71 | currentTagValues.clear();
|
---|
72 | }
|
---|
73 | tags.push(qName);
|
---|
74 | }
|
---|
75 |
|
---|
76 | @Override public void characters(char[] ch, int start, int length) {
|
---|
77 | String peek = tags.peek();
|
---|
78 | if (peek.equals("time") || peek.equals("name") || peek.equals("link") || peek.equals("symbol")) {
|
---|
79 | String tag = tags.pop();
|
---|
80 | if (tags.empty() || (!tags.peek().equals("wpt") && !tags.peek().equals("trkpt"))) {
|
---|
81 | tags.push(tag);
|
---|
82 | return;
|
---|
83 | }
|
---|
84 | String contents = new String(ch, start, length);
|
---|
85 | String oldContents = currentTagValues.get(peek);
|
---|
86 | if (oldContents == null) {
|
---|
87 | currentTagValues.put(peek, contents);
|
---|
88 | } else {
|
---|
89 | currentTagValues.put(peek, oldContents + contents);
|
---|
90 | }
|
---|
91 | tags.push(tag);
|
---|
92 | }
|
---|
93 | }
|
---|
94 |
|
---|
95 | @Override public void endElement(String namespaceURI, String localName, String qName) {
|
---|
96 | if (qName.equals("trkpt")) {
|
---|
97 | current.add(new GpsPoint(currentLatLon, currentTagValues.get("time")));
|
---|
98 | currentTagValues.clear();
|
---|
99 | } else if (qName.equals("wpt")) {
|
---|
100 | Marker m = Marker.createMarker(currentLatLon, currentTagValues, relativeMarkerPath);
|
---|
101 | if (m != null)
|
---|
102 | markerData.add(m);
|
---|
103 | currentTagValues.clear();
|
---|
104 | } else if (qName.equals("trkseg") || qName.equals("trk") || qName.equals("gpx")) {
|
---|
105 | newTrack();
|
---|
106 | currentTagValues.clear();
|
---|
107 | }
|
---|
108 | tags.pop();
|
---|
109 | }
|
---|
110 |
|
---|
111 | private void newTrack() {
|
---|
112 | if (!current.isEmpty()) {
|
---|
113 | trackData.add(current);
|
---|
114 | current = new LinkedList<GpsPoint>();
|
---|
115 | }
|
---|
116 | }
|
---|
117 | }
|
---|
118 |
|
---|
119 | /**
|
---|
120 | * Parse the input stream and store the result in trackData and markerData
|
---|
121 | *
|
---|
122 | * @param relativeMarkerPath The directory to use as relative path for all <wpt>
|
---|
123 | * marker tags. Maybe <code>null</code>, in which case no relative urls are constructed for the markers.
|
---|
124 | */
|
---|
125 | public RawGpsReader(InputStream source, File relativeMarkerPath) throws SAXException, IOException {
|
---|
126 | this.relativeMarkerPath = relativeMarkerPath;
|
---|
127 | Parser parser = new Parser();
|
---|
128 | parser.parse(new InputStreamReader(source, "UTF-8"));
|
---|
129 | }
|
---|
130 | }
|
---|