Changeset 1167 in josm
- Timestamp:
- 2008-12-23T14:32:30+01:00 (16 years ago)
- Location:
- trunk/src/org/openstreetmap/josm
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/actions/OpenFileAction.java
r1146 r1167 119 119 } 120 120 } 121 122 private void showNmeaInfobox(boolean success, NmeaReader r) { 123 String msg = tr("Coordinates imported: ") + r.getNumberOfCoordinates() + "\n" + 124 tr("Malformed sentences: ") + r.getParserMalformed() + "\n" + 125 tr("Checksum errors: ") + r.getParserChecksumErrors() + "\n"; 126 if(!success) // don't scare the user unneccessarily 127 msg += tr("Unknown sentences: ") + r.getParserUnknown() + "\n"; 128 msg += tr("Zero coordinates: ") + r.getParserZeroCoordinates(); 129 if(success) { 130 JOptionPane.showMessageDialog( 131 Main.parent, msg, 132 tr("NMEA import success"),JOptionPane.INFORMATION_MESSAGE); 133 } else { 134 JOptionPane.showMessageDialog( 135 Main.parent, msg, 136 tr("NMEA import faliure!"),JOptionPane.ERROR_MESSAGE); 137 } 138 } 121 139 122 140 private void openFileAsNmea(File file) throws IOException, FileNotFoundException { … … 124 142 if (ExtensionFileFilter.filters[ExtensionFileFilter.NMEA].acceptName(fn)) { 125 143 NmeaReader r = new NmeaReader(new FileInputStream(file), file.getAbsoluteFile().getParentFile()); 126 r.data.storageFile = file; 127 GpxLayer gpxLayer = new GpxLayer(r.data, fn); 128 Main.main.addLayer(gpxLayer); 129 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 130 MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer); 131 if (ml.data.size() > 0) { 132 Main.main.addLayer(ml); 144 if(r.getNumberOfCoordinates()>0) { 145 r.data.storageFile = file; 146 GpxLayer gpxLayer = new GpxLayer(r.data, fn); 147 Main.main.addLayer(gpxLayer); 148 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 149 MarkerLayer ml = new MarkerLayer(r.data, tr("Markers from {0}", fn), file, gpxLayer); 150 if (ml.data.size() > 0) { 151 Main.main.addLayer(ml); 152 } 133 153 } 134 154 } 135 155 showNmeaInfobox(r.getNumberOfCoordinates()>0, r); 136 156 } else { 137 157 throw new IllegalStateException(); -
trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java
r813 r1167 35 35 * Convert the time stamp of the waypoint into seconds from the epoch 36 36 */ 37 public final static SimpleDateFormat GPXTIMEFMT = 38 new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss.SSS"); // ignore timezone 39 37 40 public void setTime() { 38 41 if (! attr.containsKey("time")) { 39 42 return; 40 43 } 41 SimpleDateFormat f = new SimpleDateFormat("yyyy-MM-dd'T'HH:mm:ss"); // ignore timezone 42 Date d = f.parse(attr.get("time").toString(), new ParsePosition(0)); 44 Date d = GPXTIMEFMT.parse(attr.get("time").toString(), new ParsePosition(0)); 43 45 if (d != null /* parsing ok */) { 44 46 time = d.getTime() / 1000.0; /* ms => seconds */ -
trunk/src/org/openstreetmap/josm/io/NmeaReader.java
r1056 r1167 8 8 import java.io.InputStream; 9 9 import java.io.InputStreamReader; 10 import java.text.ParsePosition; 11 import java.text.SimpleDateFormat; 10 12 import java.util.ArrayList; 11 13 import java.util.Arrays; 12 14 import java.util.Collection; 15 import java.util.Date; 13 16 14 17 import org.openstreetmap.josm.data.coor.LatLon; … … 20 23 * Read a nmea file. Based on information from 21 24 * http://www.kowoma.de/gps/zusatzerklaerungen/NMEA.htm 22 * 25 * 23 26 * @author cbrill 24 27 */ … … 33 36 GPGGA("$GPGGA"), 34 37 /** SA = satellites active. */ 35 GPGSA("$GPGSA"); 38 GPGSA("$GPGSA"), 39 /** Course over ground and ground speed */ 40 GPVTG("$GPVTG"); 36 41 37 42 private final String type; … … 50 55 } 51 56 52 private static final int TYPE = 0; 57 // GPVTG 58 public static enum GPVTG { 59 COURSE(1),COURSE_REF(2), // true course 60 COURSE_M(3), COURSE_M_REF(4), // magnetic course 61 SPEED_KN(5), SPEED_KN_UNIT(6), // speed in knots 62 SPEED_KMH(7), SPEED_KMH_UNIT(8), // speed in km/h 63 REST(9); // version-specific rest 64 65 public final int position; 66 67 GPVTG(int position) { 68 this.position = position; 69 } 70 } 53 71 54 72 // The following only applies to GPRMC … … 56 74 TIME(1), 57 75 /** Warning from the receiver (A = data ok, V = warning) */ 58 RECEIVER_WARNING(2), 59 WIDTH_NORTH(3), WIDTH_NORTH_NAME(4), 60 LENGTH_EAST(5), LENGTH_EAST_NAME(6), 61 /** Speed in knots */ 62 SPEED(7), COURSE(8), DATE(9), 63 /** magnetic declination */ 64 MAGNETIC_DECLINATION(10), UNKNOWN(11), 76 RECEIVER_WARNING(2), 77 WIDTH_NORTH(3), WIDTH_NORTH_NAME(4), // Latitude, NS 78 LENGTH_EAST(5), LENGTH_EAST_NAME(6), // Longitude, EW 79 SPEED(7), COURSE(8), DATE(9), // Speed in knots 80 MAGNETIC_DECLINATION(10), UNKNOWN(11), // magnetic declination 65 81 /** 66 82 * Mode (A = autonom; D = differential; E = estimated; N = not valid; S 67 83 * = simulated) 68 * 84 * 69 85 * @since NMEA 2.3 70 86 */ … … 86 102 */ 87 103 QUALITY(6), SATELLITE_COUNT(7), 88 /** HDOP (horizontal dilution of precision) */ 89 HDOP(8), 90 /** height above NN (above geoid) */ 91 HEIGHT(9), HEIGHT_UNTIS(10), 92 /** height geoid - height ellipsoid (WGS84) */ 93 HEIGHT_2(11), HEIGHT_2_UNTIS(12); 104 HDOP(8), // HDOP (horizontal dilution of precision) 105 HEIGHT(9), HEIGHT_UNTIS(10), // height above NN (above geoid) 106 HEIGHT_2(11), HEIGHT_2_UNTIS(12), // height geoid - height ellipsoid (WGS84) 107 GPS_AGE(13),// Age of differential GPS data 108 REF(14); // REF station 94 109 95 110 public final int position; 96 97 111 GPGGA(int position) { 98 112 this.position = position; … … 100 114 } 101 115 102 // The following only applies to GPGGA103 116 public static enum GPGSA { 104 117 AUTOMATIC(1), 105 /** 1 = not fixed, 2 = 2D fixed, 3 = 3D fixed) */ 106 FIX_TYPE(2), 118 FIX_TYPE(2), // 1 = not fixed, 2 = 2D fixed, 3 = 3D fixed) 107 119 // PRN numbers for max 12 satellites 108 PRN_1(3), PRN_2(4), PRN_3(5), PRN_4(6), PRN_5(7), PRN_6(8), PRN_7(9), PRN_8( 109 10), PRN_9(11), PRN_10(12), PRN_11(13), PRN_12(14), 110 /** PDOP (precision) */ 111 PDOP(15), 112 /** HDOP (horizontal precision) */ 113 HDOP(16), 114 /** VDOP (vertical precision) */ 115 VDOP(17), ; 120 PRN_1(3), PRN_2(4), PRN_3(5), PRN_4(6), PRN_5(7), PRN_6(8), 121 PRN_7(9), PRN_8(10), PRN_9(11), PRN_10(12), PRN_11(13), PRN_12(14), 122 PDOP(15), // PDOP (precision) 123 HDOP(16), // HDOP (horizontal precision) 124 VDOP(17), ; // VDOP (vertical precision) 116 125 117 126 public final int position; 118 119 127 GPGSA(int position) { 120 128 this.position = position; … … 124 132 public GpxData data; 125 133 134 // private final static SimpleDateFormat GGATIMEFMT = 135 // new SimpleDateFormat("HHmmss.SSS"); 136 private final static SimpleDateFormat RMCTIMEFMT = 137 new SimpleDateFormat("ddMMyyHHmmss.SSS"); 138 139 // functons for reading the error stats 140 public NMEAParserState ps; 141 142 public int getParserUnknown() { 143 return ps.unknown; 144 } 145 public int getParserZeroCoordinates() { 146 return ps.zero_coord; 147 } 148 public int getParserChecksumErrors() { 149 return ps.checksum_errors; 150 } 151 public int getParserMalformed() { 152 return ps.malformed; 153 } 154 public int getNumberOfCoordinates() { 155 return ps.success; 156 } 157 126 158 public NmeaReader(InputStream source, File relativeMarkerPath) { 159 160 // create the data tree 127 161 data = new GpxData(); 128 162 GpxTrack currentTrack = new GpxTrack(); 129 Collection<WayPoint> currentTrackSeg = new ArrayList<WayPoint>();130 currentTrack.trackSegs.add(currentTrackSeg);131 163 data.tracks.add(currentTrack); 132 164 133 BufferedReader rd;134 String nmeaWithChecksum;135 136 165 try { 137 rd = new BufferedReader(new InputStreamReader(source)); 138 while ((nmeaWithChecksum = rd.readLine()) != null) { 139 String[] nmeaAndChecksum = nmeaWithChecksum.split("\\*"); 140 String nmea = nmeaAndChecksum[0]; 141 // XXX: No need for it: String checksum = nmeaAndChecksum[1]; 142 String[] e = nmea.split(","); 143 if (e.length == 0) { 144 continue; 145 } 146 if (NMEA_TYPE.GPRMC.equals(e[TYPE])) { 147 LatLon latLon = parseLatLon(e); 148 if (latLon == null) { 149 continue; 166 BufferedReader rd = 167 new BufferedReader(new InputStreamReader(source)); 168 169 StringBuffer sb = new StringBuffer(1024); 170 int loopstart_char = rd.read(); 171 if(loopstart_char == -1) {// zero size file 172 //TODO tell user about the problem? 173 return; 174 } 175 sb.append((char)loopstart_char); 176 ps = new NMEAParserState(); 177 ps.p_Date="010100"; // TODO date problem 178 while(true) { 179 // don't load unparsable files completely to memory 180 if(sb.length()>=1020) sb.delete(0, sb.length()-1); 181 int c = rd.read(); 182 if(c=='$') { 183 ParseNMEASentence(sb.toString(), ps); 184 sb.delete(0, sb.length()); 185 sb.append('$'); 186 } else if(c == -1) { 187 // EOF: add last WayPoint if it works out 188 ParseNMEASentence(sb.toString(),ps); 189 break; 190 } else sb.append((char)c); 191 } 192 rd.close(); 193 Object[] wparr = ps.waypoints.toArray(); 194 currentTrack.trackSegs.add(ps.waypoints); 195 data.recalculateBounds(); 196 197 } catch (final IOException e) { 198 // TODO tell user about the problem? 199 } 200 } 201 private class NMEAParserState { 202 protected Collection<WayPoint> waypoints = new ArrayList<WayPoint>(); 203 protected String p_Time; 204 protected String p_Date; 205 protected WayPoint p_Wp; 206 207 protected int success = 0; // number of successfully parsend sentences 208 protected int malformed = 0; 209 protected int checksum_errors = 0; 210 protected int unknown = 0; 211 protected int zero_coord = 0; 212 } 213 214 // Parses split up sentences into WayPoints which are stored 215 // in the collection in the NMEAParserState object. 216 // Returns true if the input made sence, false otherwise. 217 private boolean ParseNMEASentence(String s, NMEAParserState ps) { 218 try { 219 if(s.equals("")) throw(null); 220 221 // checksum check: 222 // the bytes between the $ and the * are xored; 223 // if there is no * or other meanities it will throw 224 // and result in a malformed packet. 225 String[] chkstrings = s.split("\\*"); 226 byte[] chb = chkstrings[0].getBytes(); 227 int chk=0; 228 for(int i = 1; i < chb.length; i++) chk ^= chb[i]; 229 if(Integer.parseInt(chkstrings[1].substring(0,2),16) != chk) { 230 //System.out.println("Checksum error"); 231 ps.checksum_errors++; 232 ps.p_Wp=null; 233 return false; 234 } 235 // now for the content 236 String[] e = chkstrings[0].split(","); 237 String accu; 238 239 WayPoint currentwp = ps.p_Wp; 240 String currentDate = ps.p_Date; 241 242 // handle the packet content 243 if(e[0].equals("$GPGGA")) { 244 // Position 245 LatLon latLon = parseLatLon( 246 e[GPGGA.LATITUDE_NAME.position], 247 e[GPGGA.LONGITUDE_NAME.position], 248 e[GPGGA.LATITUDE.position], 249 e[GPGGA.LONGITUDE.position] 250 ); 251 if(latLon==null) throw(null); // malformed 252 253 if((latLon.lat()==0.0) && (latLon.lon()==0.0)) { 254 ps.zero_coord++; 255 return false; 256 } 257 258 // time 259 accu = e[GPGGA.TIME.position]; 260 Date d = RMCTIMEFMT.parse(currentDate+accu, new ParsePosition(0)); 261 if (d == null) throw(null); // malformed 262 263 if((ps.p_Time==null) || (currentwp==null) || !ps.p_Time.equals(accu)) { 264 // this node is newer than the previous, create a new waypoint. 265 // no matter if previous WayPoint was null, we got something 266 // better now. 267 ps.p_Time=accu; 268 currentwp = new WayPoint(latLon); 269 } 270 if(!currentwp.attr.containsKey("time")) { 271 // As this sentence has no complete time only use it 272 // if there is no time so far 273 String gpxdate = WayPoint.GPXTIMEFMT.format(d); 274 currentwp.attr.put("time", gpxdate); 275 } 276 // elevation 277 accu=e[GPGGA.HEIGHT_UNTIS.position]; 278 if(accu.equals("M")) { 279 // Ignore heights that are not in meters for now 280 accu=e[GPGGA.HEIGHT.position]; 281 if(!accu.equals("")) { 282 Double.parseDouble(accu); 283 // if it throws it's malformed; this should only happen if the 284 // device sends nonstandard data. 285 if(!accu.equals("")) currentwp.attr.put("ele", accu); 150 286 } 151 WayPoint currentWayPoint = new WayPoint(latLon); 152 currentTrackSeg.add(currentWayPoint); 153 } 154 } 155 rd.close(); 156 } catch (final IOException e) { 157 System.out.println("Error reading file"); 158 } 159 160 } 161 162 private LatLon parseLatLon(String[] e) throws NumberFormatException { 163 // If the array looks bogus don't try to get valuable information from it 164 // But remember that the array is stripped of checksum and GPRMC is only 12 elements and split strips empty trailing elements 165 if (e.length < 10) { 166 return null; 167 } 168 String widthNorth = e[GPRMC.WIDTH_NORTH.position].trim(); 169 String lengthEast = e[GPRMC.LENGTH_EAST.position].trim(); 170 if ("".equals(widthNorth) || "".equals(lengthEast)) { 171 return null; 172 } 287 } 288 // number of sattelites 289 accu=e[GPGGA.SATELLITE_COUNT.position]; 290 int sat = 0; 291 if(!accu.equals("")) { 292 sat = Integer.parseInt(accu); 293 currentwp.attr.put("sat", accu); 294 } 295 // h-dilution 296 accu=e[GPGGA.HDOP.position]; 297 if(!accu.equals("")) { 298 Double.parseDouble(accu); 299 currentwp.attr.put("hdop", accu); 300 } 301 // fix 302 accu=e[GPGGA.QUALITY.position]; 303 if(!accu.equals("")) { 304 int fixtype = Integer.parseInt(accu); 305 switch(fixtype) { 306 case 0: 307 currentwp.attr.put("fix", "none"); 308 break; 309 case 1: 310 if(sat < 4) currentwp.attr.put("fix", "2d"); 311 else currentwp.attr.put("fix", "3d"); 312 break; 313 case 2: 314 currentwp.attr.put("fix", "dgps"); 315 break; 316 default: 317 break; 318 } 319 } 320 } else if(e[0].equals("$GPVTG")) { 321 // COURSE 322 accu = e[GPVTG.COURSE_REF.position]; 323 if(accu.equals("T")) { 324 // other values than (T)rue are ignored 325 accu = e[GPVTG.COURSE.position]; 326 if(!accu.equals("")) { 327 Double.parseDouble(accu); 328 currentwp.attr.put("course", accu); 329 } 330 } 331 // SPEED 332 accu = e[GPVTG.SPEED_KMH_UNIT.position]; 333 if(accu.startsWith("K")) { 334 accu = e[GPVTG.SPEED_KMH.position]; 335 if(!accu.equals("")) { 336 double speed = Double.parseDouble(accu); 337 speed /= 3.6; // speed in m/s 338 currentwp.attr.put("speed", Double.toString(speed)); 339 } 340 } 341 } else if(e[0].equals("$GPGSA")) { 342 // vdop 343 accu=e[GPGSA.VDOP.position]; 344 if(!accu.equals("")) { 345 Double.parseDouble(accu); 346 currentwp.attr.put("vdop", accu); 347 } 348 // hdop 349 accu=e[GPGSA.HDOP.position]; 350 if(!accu.equals("")) { 351 Double.parseDouble(accu); 352 currentwp.attr.put("hdop", accu); 353 } 354 // pdop 355 accu=e[GPGSA.PDOP.position]; 356 if(!accu.equals("")) { 357 Double.parseDouble(accu); 358 currentwp.attr.put("pdop", accu); 359 } 360 } 361 else if(e[0].equals("$GPRMC")) { 362 // coordinates 363 LatLon latLon = parseLatLon( 364 e[GPRMC.WIDTH_NORTH_NAME.position], 365 e[GPRMC.LENGTH_EAST_NAME.position], 366 e[GPRMC.WIDTH_NORTH.position], 367 e[GPRMC.LENGTH_EAST.position] 368 ); 369 if(latLon==null) throw(null); 370 if((latLon.lat()==0.0) && (latLon.lon()==0.0)) { 371 ps.zero_coord++; 372 return false; 373 } 374 // time 375 currentDate = e[GPRMC.DATE.position]; 376 String time = e[GPRMC.TIME.position]; 377 378 Date d = RMCTIMEFMT.parse(currentDate+time, new ParsePosition(0)); 379 if (d == null) throw(null); 380 381 if((ps.p_Time==null) || (currentwp==null) || !ps.p_Time.equals(time)) { 382 // this node is newer than the previous, create a new waypoint. 383 ps.p_Time=time; 384 currentwp = new WayPoint(latLon); 385 } 386 // time: this sentence has complete time so always use it. 387 String gpxdate = WayPoint.GPXTIMEFMT.format(d); 388 currentwp.attr.put("time", gpxdate); 389 // speed 390 accu = e[GPRMC.SPEED.position]; 391 if(!accu.equals("") && !currentwp.attr.containsKey("speed")) { 392 double speed = Double.parseDouble(accu); 393 speed *= 0.514444444; // to m/s 394 currentwp.attr.put("speed", Double.toString(speed)); 395 } 396 // course 397 accu = e[GPRMC.COURSE.position]; 398 if(!accu.equals("") && !currentwp.attr.containsKey("course")) { 399 Double.parseDouble(accu); 400 currentwp.attr.put("course", accu); 401 } 402 403 // TODO fix? 404 // * Mode (A = autonom; D = differential; E = estimated; N = not valid; S 405 // * = simulated) 406 // * 407 // * @since NMEA 2.3 408 // 409 //MODE(12); 410 } else { 411 ps.unknown++; 412 return false; 413 } 414 ps.p_Date = currentDate; 415 if(ps.p_Wp != currentwp) { 416 if(ps.p_Wp!=null) { 417 ps.p_Wp.setTime(); 418 } 419 ps.p_Wp = currentwp; 420 ps.waypoints.add(currentwp); 421 ps.success++; 422 return true; 423 } 424 return true; 425 426 } catch(Exception x) { 427 // out of bounds and such 428 //System.out.println("Malformed line: "+s.toString().trim()); 429 ps.malformed++; 430 ps.p_Wp=null; 431 return false; 432 } 433 } 434 435 private LatLon parseLatLon(String ew, String ns, String dlat, String dlon) 436 throws NumberFormatException { 437 String widthNorth = dlat.trim(); 438 String lengthEast = dlon.trim(); 439 440 // return a zero latlon instead of null so it is logged as zero coordinate 441 // instead of malformed sentence 442 if(widthNorth.equals("")&&lengthEast.equals("")) return new LatLon(0.0,0.0); 173 443 174 444 // The format is xxDDLL.LLLL … … 177 447 // LL.LLLL (double) latidude 178 448 int latdegsep = widthNorth.indexOf('.') - 2; 179 if (latdegsep < 0) { 180 return null; 181 } 449 if (latdegsep < 0) return null; 450 182 451 int latdeg = Integer.parseInt(widthNorth.substring(0, latdegsep)); 183 452 double latmin = Double.parseDouble(widthNorth.substring(latdegsep)); 184 453 double lat = latdeg + latmin / 60; 185 if ("S".equals(e[GPRMC.WIDTH_NORTH_NAME.position])) { 454 if ("S".equals(ns)) { 455 if(!ew.equals("N")) return null; 186 456 lat = -lat; 187 } 457 } 188 458 189 459 int londegsep = lengthEast.indexOf('.') - 2; 190 if (londegsep < 0) { 191 return null; 192 } 460 if (londegsep < 0) return null; 461 193 462 int londeg = Integer.parseInt(lengthEast.substring(0, londegsep)); 194 463 double lonmin = Double.parseDouble(lengthEast.substring(londegsep)); 195 464 double lon = londeg + lonmin / 60; 196 if ("W".equals(e[GPRMC.LENGTH_EAST_NAME.position])) { 465 if ("W".equals(ew)) { 466 if(!ew.equals("E")) return null; 197 467 lon = -lon; 198 468 } 199 200 469 return new LatLon(lat, lon); 201 470 }
Note:
See TracChangeset
for help on using the changeset viewer.