Changeset 29178 in osm for applications/editors/josm/plugins/ColumbusCSV
- Timestamp:
- 2013-01-07T22:17:29+01:00 (12 years ago)
- Location:
- applications/editors/josm/plugins/ColumbusCSV/src/org/openstreetmap/josm/plugins/columbusCSV
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/ColumbusCSV/src/org/openstreetmap/josm/plugins/columbusCSV/ColumbusCSVImporter.java
r28420 r29178 17 17 import static org.openstreetmap.josm.tools.I18n.tr; 18 18 19 import java.io.BufferedReader; 20 import java.io.DataInputStream; 19 21 import java.io.File; 22 import java.io.FileInputStream; 23 import java.io.FileNotFoundException; 20 24 import java.io.IOException; 25 import java.io.InputStreamReader; 26 21 27 import org.openstreetmap.josm.Main; 22 28 import org.openstreetmap.josm.actions.AutoScaleAction; … … 24 30 import org.openstreetmap.josm.data.gpx.GpxData; 25 31 import org.openstreetmap.josm.gui.layer.GpxLayer; 26 import org.openstreetmap.josm.gui.layer.markerlayer.Marker;27 32 import org.openstreetmap.josm.gui.layer.markerlayer.MarkerLayer; 28 33 import org.openstreetmap.josm.gui.progress.NullProgressMonitor; … … 37 42 */ 38 43 public class ColumbusCSVImporter extends FileImporter { 39 40 44 public static final String COLUMBUS_FILE_EXT = "csv"; 45 public static final String COLUMBUS_FILE_EXT_DOT = "." + COLUMBUS_FILE_EXT; 41 46 42 public ColumbusCSVImporter() { 43 super(new ExtensionFileFilter(COLUMBUS_FILE_EXT, COLUMBUS_FILE_EXT, 44 tr("Columbus V-900 CSV Files") + " (*" + COLUMBUS_FILE_EXT_DOT 45 + ")")); 47 public ColumbusCSVImporter() { 48 super(new ExtensionFileFilter(COLUMBUS_FILE_EXT, COLUMBUS_FILE_EXT, 49 tr("Columbus V-900 CSV Files") + " (*" + COLUMBUS_FILE_EXT_DOT 50 + ")")); 51 } 52 53 @Override 54 public boolean acceptFile(File pathname) { 55 try { 56 // do some deep packet inspection... 57 boolean ok = super.acceptFile(pathname) 58 && ColumbusCSVReader.isColumbusFile(pathname); 59 return ok; 60 } catch (Exception ex) { 61 return false; 62 } 63 } 64 65 /* 66 * (non-Javadoc) 67 * 68 * @see org.openstreetmap.josm.io.FileImporter#importData(java.io.File, 69 * org.openstreetmap.josm.gui.progress.ProgressMonitor) 70 */ 71 @Override 72 public void importData(File file, ProgressMonitor progressMonitor) 73 throws IOException, IllegalDataException { 74 String fn = file.getPath(); 75 76 if (progressMonitor == null) { // make sure that there is a progress 77 // monitor... 78 progressMonitor = NullProgressMonitor.INSTANCE; 46 79 } 47 80 48 /* (non-Javadoc) 49 * @see org.openstreetmap.josm.io.FileImporter#importData(java.io.File, org.openstreetmap.josm.gui.progress.ProgressMonitor) 50 */ 51 @Override 52 public void importData(File file, ProgressMonitor progressMonitor) 53 throws IOException, IllegalDataException { 54 String fn = file.getPath(); 81 progressMonitor.beginTask(String.format( 82 tr("Importing CSV file ''%s''..."), file.getName(), 4)); 83 progressMonitor.setTicksCount(1); 55 84 56 if (progressMonitor == null) { // make sure that there is a progress 57 // monitor... 58 progressMonitor = NullProgressMonitor.INSTANCE; 59 } 85 if (fn.toLowerCase().endsWith(COLUMBUS_FILE_EXT_DOT)) { 86 try { 87 ColumbusCSVReader r = new ColumbusCSVReader(); 60 88 61 progressMonitor.beginTask(String.format(tr("Importing CSV file ''%s''..."), 62 file.getName(), 4)); 89 // transform CSV into GPX 90 GpxData gpxData = r.transformColumbusCSV(fn); 91 assert (gpxData != null); 63 92 progressMonitor.setTicksCount(1); 64 93 65 if (fn.toLowerCase().endsWith(COLUMBUS_FILE_EXT_DOT)) { 66 try { 67 ColumbusCSVReader r = new ColumbusCSVReader(); 94 r.dropBufferLists(); 68 95 69 // transform CSV into GPX 70 GpxData gpxData = r.transformColumbusCSV(fn); 71 progressMonitor.setTicksCount(1); 96 progressMonitor.setTicksCount(2); 72 97 73 r.dropBufferLists(); 98 GpxLayer gpxLayer = new GpxLayer(gpxData, file.getName()); 99 assert (gpxLayer != null); 74 100 75 progressMonitor.setTicksCount(2); 101 // add layer to show way points 102 Main.main.addLayer(gpxLayer); 76 103 77 GpxLayer gpxLayer = new GpxLayer(gpxData, file.getName()); 78 79 // add layer to show way points 80 Main.main.addLayer(gpxLayer); 104 progressMonitor.setTicksCount(3); 81 105 82 progressMonitor.setTicksCount(3); 106 // ... and scale view appropriately - if wished by user 107 if (ColumbusCSVPreferences.zoomAfterImport()) { 108 AutoScaleAction action = new AutoScaleAction("data"); 109 action.autoScale(); 110 } 111 progressMonitor.setTicksCount(4); 83 112 84 // ... and scale view appropriately - if wished by user 85 if (ColumbusCSVPreferences.zoomAfterImport()) { 86 AutoScaleAction action = new AutoScaleAction("data"); 87 action.autoScale(); 88 } 89 progressMonitor.setTicksCount(4); 113 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 114 try { 115 MarkerLayer ml = new MarkerLayer(gpxData, 116 tr("Markers of ") + file.getName(), file, 117 gpxLayer); 90 118 91 if (Main.pref.getBoolean("marker.makeautomarkers", true)) { 92 MarkerLayer ml = new MarkerLayer(gpxData, String.format(tr("Markers from %s"), file.getName()), file, gpxLayer); 93 if (ml.data.size() > 0) { 94 Main.main.addLayer(ml); 95 } else { 96 System.err.println("Warning: File contains no markers."); 97 } 98 /* WORKAROUND (Bugfix: #6912): Set marker offset to 0.0 to avoid message "This is after the end of the recording" 99 for (Marker marker : ml.data) { 100 marker.offset = 0.0; 101 }*/ 102 } else { 103 System.err.println("Warning: Option 'marker.makeautomarkers' is not set; audio marker layer is not created."); 104 } 105 } catch (Exception e) { 106 // catch and forward exception 107 e.printStackTrace(System.err); 108 throw new IllegalDataException(e); 109 } finally { // take care of monitor... 110 progressMonitor.finishTask(); 119 assert (ml != null); 120 assert (ml.data != null); 121 122 System.out.println("Layer: " + ml); 123 System.out.println("Data: " + ml.data != null); 124 System.out.println("Data size: " + ml.data.size()); 125 126 Main.main.addLayer(ml); 127 if (ml.data.size() > 0) { 128 129 } else { 130 System.out 131 .println("Warning: File contains no markers."); 111 132 } 133 } catch (Exception exLayer) { 134 System.out.println(exLayer); 135 exLayer.printStackTrace(System.err); 136 } 112 137 } else { 113 throw new IOException( 114 tr(String 115 .format( 116 "Unsupported file extension (file '%s' does not end with '%s')!", 117 file.getName(), COLUMBUS_FILE_EXT))); 138 System.out 139 .println("Warning: Option 'marker.makeautomarkers' is not set; audio marker layer is not created."); 118 140 } 141 } catch (Exception e) { 142 // catch and forward exception 143 e.printStackTrace(System.err); 144 throw new IllegalDataException(e); 145 } finally { // take care of monitor... 146 progressMonitor.finishTask(); 147 } 148 } else { 149 throw new IOException( 150 tr(String 151 .format("Unsupported file extension (file '%s' does not end with '%s')!", 152 file.getName(), COLUMBUS_FILE_EXT))); 119 153 } 154 } 120 155 } -
applications/editors/josm/plugins/ColumbusCSV/src/org/openstreetmap/josm/plugins/columbusCSV/ColumbusCSVReader.java
r28040 r29178 73 73 */ 74 74 public class ColumbusCSVReader { 75 public static final String AUDIO_WAV_LINK = "audio/wav"; 76 /* GPX tags not provided by the GPXReader class */ 77 private static final String VDOP_TAG = "vdop"; 78 private static final String HDOP_TAG = "hdop"; 79 private static final String PDOP_TAG = "pdop"; 80 private static final String ELEVATIONHEIGHT_TAG = "ele"; 81 private static final String TIME_TAG = "time"; 82 private static final String COMMENT_TAG = "cmt"; 83 private static final String DESC_TAG = "desc"; 84 private static final String FIX_TAG = "fix"; 85 private static final String TYPE_TAG = "columbus:type"; 86 87 private static String[] EMPTY_LINE = new String[] {}; 88 private static final String SEPS = ","; 89 90 private int dopConversionErrors = 0; 91 private int dateConversionErrors = 0; 75 public static final String AUDIO_WAV_LINK = "audio/wav"; 76 /* GPX tags not provided by the GPXReader class */ 77 private static final String VDOP_TAG = "vdop"; 78 private static final String HDOP_TAG = "hdop"; 79 private static final String PDOP_TAG = "pdop"; 80 private static final String ELEVATIONHEIGHT_TAG = "ele"; 81 private static final String TIME_TAG = "time"; 82 private static final String COMMENT_TAG = "cmt"; 83 private static final String DESC_TAG = "desc"; 84 private static final String FIX_TAG = "fix"; 85 private static final String TYPE_TAG = "columbus:type"; 86 87 private static String[] EMPTY_LINE = new String[] {}; 88 private static final String SEPS = ","; 89 /* Lines to read before deciding on Columbus file yes/no */ 90 private static final int MAX_SCAN_LINES = 20; 91 private static final int MIN_SCAN_LINES = 10; 92 93 private int dopConversionErrors = 0; 94 private int dateConversionErrors = 0; 95 96 private int firstVoxNumber = -1, lastVoxNumber = -1; 97 98 private HashMap<String, WayPoint> voxFiles = new HashMap<String, WayPoint>(); 99 private Collection<Collection<WayPoint>> allTrackPts = new ArrayList<Collection<WayPoint>>(); 100 private List<WayPoint> trackPts = new ArrayList<WayPoint>(); 101 private List<WayPoint> allWpts = new ArrayList<WayPoint>(); 102 private String fileDir; 103 104 /** 105 * Transforms a Columbus V-900 CSV file into a JOSM GPX layer. 106 * 107 * @param fileName The Columbus file to import. 108 * @return GPX representation of Columbus track file. 109 * @throws IOException 110 * @throws DataFormatException 111 */ 112 public GpxData transformColumbusCSV(String fileName) throws IOException, 113 IllegalDataException { 114 if (fileName == null || fileName.length() == 0) { 115 throw new IllegalArgumentException( 116 "File name must not be null or empty"); 117 } 118 119 // GPX data structures 120 GpxData gpxData = new GpxData(); 121 122 File f = new File(fileName); 123 fileDir = f.getParent(); 124 FileInputStream fstream = new FileInputStream(fileName); 125 // Get the object of DataInputStream 126 DataInputStream in = new DataInputStream(fstream); 127 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 128 String strLine; 129 // Initial values 130 int line = 1; 131 initImport(); 132 dropBufferLists(); 133 134 int waypts = 0, trkpts = 0, audiopts = 0, missaudio = 0, rescaudio = 0; 135 try { 136 // Read File Line By Line 137 while ((strLine = br.readLine()) != null) { 138 String[] csvFields = getCSVLine(strLine); // Get the columns of 139 // the current line 140 if (csvFields.length == 0 || line <= 1) { // Skip, if line is 141 // header or contains 142 // no data 143 ++line; 144 continue; 145 } 146 147 try { 148 WayPoint wpt = createWayPoint(csvFields, fileDir); 149 String wptType = (String) wpt.attr.get(TYPE_TAG); 150 String oldWptType = csvFields[1]; 151 152 if ("T".equals(wptType)) { // point of track (T) 153 trackPts.add(wpt); 154 trkpts++; 155 } else { // way point (C) / have voice file: V) 156 if (!wptType.equals(oldWptType)) { // type changed? 157 if ("V".equals(oldWptType)) { // missing audiofile 158 missaudio++; 159 } 160 if ("C".equals(oldWptType)) { // rescued audiofile 161 rescaudio++; 162 } 163 } else { 164 if ("V".equals(wptType)) { // wpt with vox 165 audiopts++; 166 } 167 } 168 169 gpxData.waypoints.add(wpt); // add the waypoint to the 170 // track 171 waypts++; 172 } 173 174 allWpts.add(wpt); 175 176 wpt.attr.remove(TYPE_TAG); 177 } catch (Exception ex) { 178 br.close(); 179 throw new IllegalDataException(tr("Error in line " + line 180 + ": " + ex.toString())); 181 } 182 ++line; 183 } 184 } finally { 185 // Close the input stream 186 br.close(); 187 } 188 189 // do some sanity checks 190 assert (trackPts.size() == trkpts); 191 assert (gpxData.waypoints.size() == waypts); 192 assert (firstVoxNumber <= lastVoxNumber); 193 194 rescaudio += searchForLostAudioFiles(gpxData); 195 196 // compose the track 197 allTrackPts.add(trackPts); 198 GpxTrack trk = new ImmutableGpxTrack(allTrackPts, 199 Collections.<String, Object> emptyMap()); 200 gpxData.tracks.add(trk); 201 202 assert (gpxData.routes.size() == 1); 203 204 // Issue conversion warning, if needed 205 if (ColumbusCSVPreferences.warnConversion() 206 && (dateConversionErrors > 0 || dopConversionErrors > 0)) { 207 String message = String.format( 208 "%d date conversion faults and %d DOP conversion errors", 209 dateConversionErrors, dopConversionErrors); 210 ColumbusCSVUtils.showWarningMessage(tr(message)); 211 } 212 // Show summary 213 if (ColumbusCSVPreferences.showSummary()) { 214 showSummary(waypts, trkpts, audiopts, missaudio, rescaudio); 215 } 216 217 String desc = String.format( 218 "Converted by ColumbusCSV plugin from track file '%s'", 219 f.getName()); 220 gpxData.attr.put(GpxData.META_DESC, desc); 221 gpxData.storageFile = f; 222 return gpxData; 223 } 224 225 /** 226 * Checks a (CSV) file for Columbus tags. This method is a simplified copy 227 * of the @link transformColumbusCSV and just checks a small amount of 228 * lines. 229 * 230 * @param file The file to check. 231 * @return true, if given file is a Columbus file; otherwise false. 232 */ 233 public static boolean isColumbusFile(File file) throws IOException { 234 if (file == null) return false; 92 235 93 private int firstVoxNumber = -1, lastVoxNumber = -1; 94 95 private HashMap<String, WayPoint> voxFiles = new HashMap<String, WayPoint>(); 96 private Collection<Collection<WayPoint>> allTrackPts = new ArrayList<Collection<WayPoint>>(); 97 private List<WayPoint> trackPts = new ArrayList<WayPoint>(); 98 private List<WayPoint> allWpts = new ArrayList<WayPoint>(); 99 private String fileDir; 100 101 /** 102 * Transforms a Columbus V-900 CSV file into a JOSM GPX layer. 103 * 104 * @param fileName 105 * @return 106 * @throws IOException 107 * @throws DataFormatException 108 */ 109 public GpxData transformColumbusCSV(String fileName) throws IOException, 110 IllegalDataException { 111 if (fileName == null || fileName.length() == 0) { 112 throw new IllegalArgumentException( 113 "File name must not be null or empty"); 236 FileInputStream fstream = new FileInputStream(file); 237 // Get the object of DataInputStream 238 DataInputStream in = new DataInputStream(fstream); 239 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 240 String strLine; 241 // Initial values 242 int line = 0; 243 int columbusLines = 0; 244 try { 245 // Read File Line By Line until we either exceed the maximum scan 246 // lines or we are sure that we have a columbus file 247 while ((strLine = br.readLine()) != null 248 && (line < MAX_SCAN_LINES || columbusLines > MIN_SCAN_LINES)) { 249 String[] csvFields = getCSVLine(strLine); // Get the columns of 250 // the current line 251 ++line; 252 if (csvFields.length == 0 || line <= 1) { // Skip, if line is 253 // header or contains 254 // no data 255 continue; 114 256 } 115 257 116 // GPX data structures 117 GpxData gpxData = new GpxData(); 118 119 File f = new File(fileName); 120 fileDir = f.getParent(); 121 FileInputStream fstream = new FileInputStream(fileName); 122 // Get the object of DataInputStream 123 DataInputStream in = new DataInputStream(fstream); 124 BufferedReader br = new BufferedReader(new InputStreamReader(in)); 125 String strLine; 126 // Initial values 127 int line = 1; 128 initImport(); 129 dropBufferLists(); 130 131 int waypts = 0, trkpts = 0, audiopts = 0, missaudio = 0, rescaudio = 0; 132 try { 133 // Read File Line By Line 134 while ((strLine = br.readLine()) != null) { 135 String[] csvFields = getCSVLine(strLine); // Get the columns of the current line 136 if (csvFields.length == 0 || line <= 1) { // Skip, if line is header or contains no data 137 ++line; 138 continue; 139 } 140 141 try { 142 WayPoint wpt = createWayPoint(csvFields, fileDir); 143 String wptType = (String) wpt.attr.get(TYPE_TAG); 144 String oldWptType = csvFields[1]; 145 146 if ("T".equals(wptType)) { // point of track (T) 147 trackPts.add(wpt); 148 trkpts++; 149 } else { // way point (C) / have voice file: V) 150 if (!wptType.equals(oldWptType)) { // type changed? 151 if ("V".equals(oldWptType)) { // missing audiofile 152 missaudio++; 153 } 154 if ("C".equals(oldWptType)) { // rescued audiofile 155 rescaudio++; 156 } 157 } else { 158 if ("V".equals(wptType)) { // wpt with vox 159 audiopts++; 160 } 161 } 162 163 gpxData.waypoints.add(wpt); // add the waypoint to the track 164 waypts++; 165 } 166 167 allWpts.add(wpt); 168 169 wpt.attr.remove(TYPE_TAG); 170 } catch (Exception ex) { 171 throw new IllegalDataException(tr("Error in line " + line 172 + ": " + ex.toString())); 173 } 174 ++line; 175 } 176 } finally { 177 // Close the input stream 178 in.close(); 258 String wptType = csvFields[1]; 259 // Check for columbus tag 260 if ("T".equals(wptType) || "V".equals(wptType) 261 || "C".equals(wptType)) { 262 // ok, we found one line but still not convinced ;-) 263 columbusLines++; 179 264 } 180 181 // do some sanity checks 182 assert (trackPts.size() == trkpts); 183 assert (gpxData.waypoints.size() == waypts); 184 assert (firstVoxNumber <= lastVoxNumber); 185 186 rescaudio += searchForLostAudioFiles(gpxData); 187 188 // compose the track 189 allTrackPts.add(trackPts); 190 GpxTrack trk = new ImmutableGpxTrack(allTrackPts, Collections 191 .<String, Object> emptyMap()); 192 gpxData.tracks.add(trk); 193 194 assert (gpxData.routes.size() == 1); 195 196 // Issue conversion warning, if needed 197 if (ColumbusCSVPreferences.warnConversion() 198 && (dateConversionErrors > 0 || dopConversionErrors > 0)) { 199 String message = String.format( 200 "%d date conversion faults and %d DOP conversion errors", 201 dateConversionErrors, dopConversionErrors); 202 ColumbusCSVUtils.showWarningMessage(tr(message)); 265 } 266 } finally { 267 // Close the input stream 268 br.close(); 269 } 270 271 return columbusLines > MIN_SCAN_LINES; 272 } 273 274 /** 275 * Searches for unlinked audio files and tries to link them with the closest 276 * way point. This requires that the file date of the wav files is kept - 277 * there is no other way to assign the audio files to way points. 278 * 279 * @param gpx 280 * @return 281 */ 282 private int searchForLostAudioFiles(GpxData gpx) { 283 HashMap<String, WayPoint> voxFiles = getVoxFileMap(); 284 285 int first, last; 286 first = getFirstVoxNumber(); 287 last = getLastVoxNumber(); 288 289 int rescuedFiles = 0; 290 291 for (int i = first; i < last; i++) { 292 String voxFile = String.format("vox%05d.wav", i); 293 String nextVoxFile = String.format("vox%05d.wav", i + 1); 294 if (!voxFiles.containsKey(voxFile)) { 295 System.out.println("Found lost vox file " + voxFile); 296 297 File f = getVoxFilePath(voxFile); 298 WayPoint nearestWpt = null; 299 List<WayPoint> wpts = getAllWayPoints(); 300 // Attach recording to the way point right before the next vox 301 // file 302 if (voxFiles.containsKey(nextVoxFile)) { 303 WayPoint nextWpt = voxFiles.get(nextVoxFile); 304 int idx = getAllWayPoints().indexOf(nextWpt) - 5; 305 if (idx >= 0) { 306 nearestWpt = wpts.get(idx); 307 } else { 308 nearestWpt = wpts.get(0); 309 } 310 } else { // attach to last way point 311 nearestWpt = wpts.get(wpts.size() - 1); 203 312 } 204 // Show summary 205 if (ColumbusCSVPreferences.showSummary()) { 206 showSummary(waypts, trkpts, audiopts, missaudio, rescaudio); 313 314 // Add link to found way point 315 if (nearestWpt != null) { 316 if (addLinkToWayPoint(nearestWpt, "*" + voxFile + "*", f)) { 317 System.out.println(String.format( 318 "Linked file %s to position %s", voxFile, 319 nearestWpt.getCoor().toDisplayString())); 320 // Add linked way point to way point list of GPX; 321 // otherwise 322 // it would not be shown correctly 323 gpx.waypoints.add(nearestWpt); 324 rescuedFiles++; 325 } else { 326 System.err 327 .println(String 328 .format("Could not link vox file %s due to invalid parameters.", 329 voxFile)); 330 } 207 331 } 208 209 String desc = String.format("Converted by ColumbusCSV plugin from track file '%s'", f.getName()); 210 gpxData.attr.put(GpxData.META_DESC, desc); 211 gpxData.storageFile = f; 212 return gpxData; 213 } 214 215 /** 216 * Searches for unlinked audio files and tries to link them with the closest 217 * way point. This requires that the file date of the wav files is kept - 218 * there is no other way to assign the audio files to way points. 219 * 220 * @param gpx 221 * @return 222 */ 223 private int searchForLostAudioFiles(GpxData gpx) { 224 HashMap<String,WayPoint> voxFiles = getVoxFileMap(); 225 226 int first, last; 227 first = getFirstVoxNumber(); 228 last = getLastVoxNumber(); 229 230 int rescuedFiles = 0; 231 232 for (int i = first; i < last; i++) { 233 String voxFile = String.format("vox%05d.wav", i); 234 String nextVoxFile = String.format("vox%05d.wav", i+1); 235 if (!voxFiles.containsKey(voxFile)) { 236 System.out.println("Found lost vox file " + voxFile); 237 238 File f = getVoxFilePath(voxFile); 239 WayPoint nearestWpt = null; 240 List<WayPoint> wpts = getAllWayPoints(); 241 // Attach recording to the way point right before the next vox file 242 if (voxFiles.containsKey(nextVoxFile)) { 243 WayPoint nextWpt = voxFiles.get(nextVoxFile); 244 int idx = getAllWayPoints().indexOf(nextWpt) - 5; 245 if (idx >= 0) { 246 nearestWpt = wpts.get(idx); 247 } else { 248 nearestWpt = wpts.get(0); 249 } 250 } else { // attach to last way point 251 nearestWpt = wpts.get(wpts.size() - 1); 252 } 253 254 // Add link to found way point 255 if (nearestWpt != null) { 256 if (addLinkToWayPoint(nearestWpt, "*" + voxFile + "*", f)) { 257 System.out.println(String.format( 258 "Linked file %s to position %s", voxFile, 259 nearestWpt.getCoor().toDisplayString())); 260 // Add linked way point to way point list of GPX; otherwise 261 // it would not be shown correctly 262 gpx.waypoints.add(nearestWpt); 263 rescuedFiles++; 264 } else { 265 System.err 266 .println(String 267 .format( 268 "Could not link vox file %s due to invalid parameters.", 269 voxFile)); 270 } 271 } 272 } 273 } 274 275 return rescuedFiles; 276 } 277 278 /** 332 } 333 } 334 335 return rescuedFiles; 336 } 337 338 /** 279 339 * 280 340 */ 281 private void initImport() { 282 dateConversionErrors = 0; 283 dopConversionErrors = 0; 284 firstVoxNumber = Integer.MAX_VALUE; 285 lastVoxNumber = Integer.MIN_VALUE; 286 } 287 288 /** 289 * Clears all temporary buffers. 290 */ 291 void dropBufferLists() { 292 allTrackPts.clear(); 293 trackPts.clear(); 294 voxFiles.clear(); 295 } 296 297 /** 298 * Shows the summary to the user. 299 * @param waypts The number of imported way points 300 * @param trkpts The number of imported track points 301 * @param audiopts The number of imported way points with vox 302 * @param missaudio The number of missing audio files 303 * @param rescaudio The number of rescued audio files 304 */ 305 private void showSummary(int waypts, int trkpts, int audiopts, 306 int missaudio, int rescaudio) { 307 String message = ""; 308 if (missaudio > 0) { 309 message = String 310 .format( 311 "Imported %d track points and %d way points (%d with audio, %d rescued).\nNote: %d audio files could not be found, please check marker comments!", 312 trkpts, waypts, audiopts, rescaudio, missaudio); 313 } else { 314 message = String 315 .format( 316 "Imported %d track points and %d way points (%d with audio, %d rescued).", 317 trkpts, waypts, audiopts, rescaudio); 341 private void initImport() { 342 dateConversionErrors = 0; 343 dopConversionErrors = 0; 344 firstVoxNumber = Integer.MAX_VALUE; 345 lastVoxNumber = Integer.MIN_VALUE; 346 } 347 348 /** 349 * Clears all temporary buffers. 350 */ 351 void dropBufferLists() { 352 allTrackPts.clear(); 353 trackPts.clear(); 354 voxFiles.clear(); 355 } 356 357 /** 358 * Shows the summary to the user. 359 * 360 * @param waypts 361 * The number of imported way points 362 * @param trkpts 363 * The number of imported track points 364 * @param audiopts 365 * The number of imported way points with vox 366 * @param missaudio 367 * The number of missing audio files 368 * @param rescaudio 369 * The number of rescued audio files 370 */ 371 private void showSummary(int waypts, int trkpts, int audiopts, 372 int missaudio, int rescaudio) { 373 String message = ""; 374 if (missaudio > 0) { 375 message = String 376 .format("Imported %d track points and %d way points (%d with audio, %d rescued).\nNote: %d audio files could not be found, please check marker comments!", 377 trkpts, waypts, audiopts, rescaudio, missaudio); 378 } else { 379 message = String 380 .format("Imported %d track points and %d way points (%d with audio, %d rescued).", 381 trkpts, waypts, audiopts, rescaudio); 382 } 383 ColumbusCSVUtils.showInfoMessage(tr(message)); 384 } 385 386 /** 387 * Creates a GPX way point from a tokenized CSV line. The attributes of the 388 * way point depends on whether the Columbus logger runs in simple or 389 * professional mode. 390 * 391 * @param csvLine 392 * The columns of a single CSV line. 393 * @return The corresponding way point instance. 394 * @throws DataFormatException 395 */ 396 private WayPoint createWayPoint(String[] csvLine, String fileDir) 397 throws IOException { 398 // Sample line in simple mode 399 // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE 400 // E/W,HEIGHT,SPEED,HEADING,VOX 401 // 1,T,090430,194134,48.856330N,009.089779E,318,20,0, 402 403 // Sample line in extended mode 404 // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE 405 // E/W,HEIGHT,SPEED,HEADING,FIX MODE,VALID,PDOP,HDOP,VDOP,VOX 406 // 1,T,090508,191448,48.856928N,009.091153E,330,3,0,3D,SPS ,1.4,1.2,0.8, 407 if (csvLine.length != 10 && csvLine.length != 15) 408 throw new IOException("Invalid number of tokens: " + csvLine.length); 409 boolean isExtMode = csvLine.length > 10; 410 411 // Extract latitude/longitude first 412 String lat = csvLine[4]; 413 double latVal = Double.parseDouble(lat.substring(0, lat.length() - 1)); 414 if (lat.endsWith("S")) { 415 latVal = -latVal; 416 } 417 418 String lon = csvLine[5]; 419 double lonVal = Double.parseDouble(lon.substring(0, lon.length() - 1)); 420 if (lon.endsWith("W")) { 421 lonVal = -lonVal; 422 } 423 LatLon pos = new LatLon(latVal, lonVal); 424 WayPoint wpt = new WayPoint(pos); 425 426 // set wpt type 427 wpt.attr.put(TYPE_TAG, csvLine[1]); 428 429 // Check for audio file and link it, if present 430 String voxFile = null; 431 if (isExtMode) { 432 voxFile = csvLine[14]; 433 } else { 434 voxFile = csvLine[9]; 435 } 436 437 if (!ColumbusCSVUtils.isStringNullOrEmpty(voxFile)) { 438 voxFile = voxFile + ".wav"; 439 File file = getVoxFilePath(fileDir, voxFile); 440 if (file != null && file.exists()) { 441 // link vox file 442 int voxNum = getNumberOfVoxfile(voxFile); 443 lastVoxNumber = Math.max(voxNum, lastVoxNumber); 444 firstVoxNumber = Math.min(voxNum, firstVoxNumber); 445 446 addLinkToWayPoint(wpt, voxFile, file); 447 448 if (!"V".equals(csvLine[1])) { 449 System.out 450 .println("Rescued unlinked audio file " + voxFile); 318 451 } 319 ColumbusCSVUtils.showInfoMessage(tr(message)); 320 } 321 322 /** 323 * Creates a GPX way point from a tokenized CSV line. The attributes of the 324 * way point depends on whether the Columbus logger runs in simple or 325 * professional mode. 326 * 327 * @param csvLine The columns of a single CSV line. 328 * @return The corresponding way point instance. 329 * @throws DataFormatException 330 */ 331 private WayPoint createWayPoint(String[] csvLine, String fileDir) 332 throws IOException { 333 // Sample line in simple mode 334 // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE 335 // E/W,HEIGHT,SPEED,HEADING,VOX 336 // 1,T,090430,194134,48.856330N,009.089779E,318,20,0, 337 338 // Sample line in extended mode 339 // INDEX,TAG,DATE,TIME,LATITUDE N/S,LONGITUDE 340 // E/W,HEIGHT,SPEED,HEADING,FIX MODE,VALID,PDOP,HDOP,VDOP,VOX 341 // 1,T,090508,191448,48.856928N,009.091153E,330,3,0,3D,SPS ,1.4,1.2,0.8, 342 if (csvLine.length != 10 && csvLine.length != 15) 343 throw new IOException("Invalid number of tokens: " + csvLine.length); 344 boolean isExtMode = csvLine.length > 10; 345 346 // Extract latitude/longitude first 347 String lat = csvLine[4]; 348 double latVal = Double.parseDouble(lat.substring(0, lat.length() - 1)); 349 if (lat.endsWith("S")) { 350 latVal = -latVal; 452 voxFiles.put(voxFile, wpt); 453 454 // set type to way point with vox 455 wpt.attr.put(TYPE_TAG, "V"); 456 } else { // audio file not found -> issue warning 457 System.err.println("File " + voxFile + " not found!"); 458 String warnMsg = tr("Missing audio file") + ": " + voxFile; 459 System.err.println(warnMsg); 460 if (ColumbusCSVPreferences.warnMissingAudio()) { 461 ColumbusCSVUtils.showInfoMessage(warnMsg); 351 462 } 352 353 String lon = csvLine[5]; 354 double lonVal = Double.parseDouble(lon.substring(0, lon.length() - 1)); 355 if (lon.endsWith("W")) { 356 lonVal = -lonVal; 357 } 358 LatLon pos = new LatLon(latVal, lonVal); 359 WayPoint wpt = new WayPoint(pos); 360 361 // set wpt type 362 wpt.attr.put(TYPE_TAG, csvLine[1]); 363 364 // Check for audio file and link it, if present 365 String voxFile = null; 366 if (isExtMode) { 367 voxFile = csvLine[14]; 368 } else { 369 voxFile = csvLine[9]; 370 } 371 372 if (!ColumbusCSVUtils.isStringNullOrEmpty(voxFile)) { 373 voxFile = voxFile + ".wav"; 374 File file = getVoxFilePath(fileDir, voxFile); 375 if (file != null && file.exists()) { 376 // link vox file 377 int voxNum = getNumberOfVoxfile(voxFile); 378 lastVoxNumber = Math.max(voxNum, lastVoxNumber); 379 firstVoxNumber = Math.min(voxNum, firstVoxNumber); 380 381 addLinkToWayPoint(wpt, voxFile, file); 382 383 if (!"V".equals(csvLine[1])) { 384 System.out.println("Rescued unlinked audio file " + voxFile); 385 } 386 voxFiles.put(voxFile, wpt); 387 388 // set type to way point with vox 389 wpt.attr.put(TYPE_TAG, "V"); 390 } else { // audio file not found -> issue warning 391 System.err.println("File " + voxFile + " not found!"); 392 String warnMsg = tr("Missing audio file") + ": " + voxFile; 393 System.err.println(warnMsg); 394 if (ColumbusCSVPreferences.warnMissingAudio()) { 395 ColumbusCSVUtils.showInfoMessage(warnMsg); 396 } 397 wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, warnMsg); 398 // set type to ordinary way point 399 wpt.attr.put(TYPE_TAG, "C"); 400 } 401 402 } 403 404 // Extract date/time 405 SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyMMdd/HHmmss"); 406 Date d = null; 407 408 try { 409 410 d = sdf.parse(csvLine[2] + "/" + csvLine[3]); 411 // format date according to GPX 412 SimpleDateFormat f = new SimpleDateFormat( 413 "yyyy-MM-dd'T'HH:mm:ss'Z'"); 414 415 wpt.attr.put(ColumbusCSVReader.TIME_TAG, f.format(d).toString()); 416 wpt.setTime(); 417 } catch (ParseException ex) { 418 dateConversionErrors++; 419 System.err.println(ex); 420 } 421 422 // Add further attributes 423 // Elevation height (altitude provided by GPS signal) 424 wpt.attr.put(ColumbusCSVReader.ELEVATIONHEIGHT_TAG, csvLine[6]); 425 426 // Add data of extended mode, if applicable 427 if (isExtMode && !ColumbusCSVPreferences.ignoreDOP()) { 428 addExtendedGPSData(csvLine, wpt); 429 } 430 431 return wpt; 432 } 433 434 /** 435 * Gets the full path of the audio file. Same as <code>getVoxFilePath(getWorkingDirOfImport(), voxFile)</code>. 436 * @param voxFile The name of the audio file without dir and extension. 437 * @return 438 * 439 */ 440 public File getVoxFilePath(String voxFile) { 441 return getVoxFilePath(getWorkingDirOfImport(), voxFile); 442 } 443 444 /** 445 * Gets the full path of the audio file. 446 * @param fileDir The directory containing the audio file. 447 * @param voxFile The name of the audio file without dir and extension. 448 * @return 449 */ 450 public File getVoxFilePath(String fileDir, String voxFile) { 451 // The FAT16 file name is interpreted differently from case-sensitive file systems, so we 452 // have to test several variants 453 String[] fileNameVariants = new String[] {voxFile, voxFile.toLowerCase(), voxFile.toUpperCase()}; 454 455 for (int i = 0; i < fileNameVariants.length; i++) { 456 File file = new File(fileDir + File.separator + fileNameVariants[i]); 457 if (file.exists()) { 458 return file; 459 } 460 } 461 return null; // give up... 462 463 } 464 465 /** 466 * Adds extended GPS data (*DOP and fix mode) to the way point 467 * @param csvLine 468 * @param wpt 469 */ 470 private void addExtendedGPSData(String[] csvLine, WayPoint wpt) { 471 // Fix mode 472 wpt.attr.put(FIX_TAG, csvLine[9].toLowerCase()); 473 474 Float f; 475 // Position errors (dop = dilution of position) 476 f = ColumbusCSVUtils.floatFromString(csvLine[11]); 477 if (f != Float.NaN) { 478 wpt.attr.put(ColumbusCSVReader.PDOP_TAG, f); 479 } else { 480 dopConversionErrors++; 481 } 482 483 f = ColumbusCSVUtils.floatFromString(csvLine[12]); 484 if (f != Float.NaN) { 485 wpt.attr.put(ColumbusCSVReader.HDOP_TAG, f); 486 } else { 487 dopConversionErrors++; 488 } 489 490 f = ColumbusCSVUtils.floatFromString(csvLine[13]); 491 if (f != Float.NaN) { 492 wpt.attr.put(ColumbusCSVReader.VDOP_TAG, f); 493 } else { 494 dopConversionErrors++; 495 } 496 } 497 498 /** 499 * Adds a link to a way point. 500 * @param wpt The way point to add the link to. 501 * @param voxFile 502 * @param file 503 * @return True, if link has been added; otherwise false 504 */ 505 public boolean addLinkToWayPoint(WayPoint wpt, String voxFile, File file) { 506 if (file == null || wpt == null || voxFile == null) return false; 507 508 GpxLink lnk = new GpxLink(file.toURI().toString()); 509 lnk.type = ColumbusCSVReader.AUDIO_WAV_LINK; 510 lnk.text = voxFile; 511 512 // JOSM expects a collection of links here... 513 Collection<GpxLink> linkList = new ArrayList<GpxLink>(1); 514 linkList.add(lnk); 515 516 wpt.attr.put(GpxData.META_LINKS, linkList); 517 wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, "Audio recording"); 518 wpt.attr.put(ColumbusCSVReader.DESC_TAG, voxFile); 519 return true; 520 } 521 522 /** 523 * Splits a line of the CSV files into it's tokens. 524 * 525 * @param line 526 * @return Array containing the tokens of the CSV file. 527 */ 528 private String[] getCSVLine(String line) { 529 if (line == null || line.length() == 0) 530 return EMPTY_LINE; 531 532 StringTokenizer st = new StringTokenizer(line, SEPS, false); 533 int n = st.countTokens(); 534 535 String[] res = new String[n]; 536 for (int i = 0; i < n; i++) { 537 res[i] = st.nextToken().trim(); 538 } 539 return res; 540 } 541 542 /** 543 * Extracts the number from a VOX file name, e. g. for a 544 * file named "VOX01524" this method will return 1524. 545 * @param fileName The vox file name. 546 * @return The number of the vox file or -1; if the given name was not valid. 547 */ 548 private int getNumberOfVoxfile(String fileName) { 549 if (fileName == null) return -1; 550 551 try { 552 String num = fileName.substring(3); 553 int val = Integer.parseInt(num); 554 return val; 555 } catch (NumberFormatException e) { 556 return -1; 557 } 558 } 559 560 /** 561 * Return the number of date conversion errors. 562 * 563 * @return 564 */ 565 public int getNumberOfDateConversionErrors() { 566 return dateConversionErrors; 567 } 568 569 /** 570 * Return the number of pdop/vdop/hdop conversion errors. 571 * 572 * @return 573 */ 574 public int getNumberOfDOPConversionErrors() { 575 return dopConversionErrors; 576 } 577 578 /** 579 * Gets the number of first vox file. 580 * @return 581 */ 582 public int getFirstVoxNumber() { 583 return firstVoxNumber; 584 } 585 586 /** 587 * Gets the number of last vox file. 588 * @return 589 */ 590 public int getLastVoxNumber() { 591 return lastVoxNumber; 592 } 593 594 /** 595 * Gets the map containing the vox files with their associated way point. 596 * @return 597 */ 598 public HashMap<String, WayPoint> getVoxFileMap() { 599 return voxFiles; 600 } 601 602 /** 603 * Gets the list containing all imported track and way points. 604 * @return 605 */ 606 public List<WayPoint> getAllWayPoints() { 607 return allWpts; 608 } 609 610 /** 611 * Gets the import directory. 612 * @return 613 */ 614 public String getWorkingDirOfImport() { 615 return fileDir; 616 } 463 wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, warnMsg); 464 // set type to ordinary way point 465 wpt.attr.put(TYPE_TAG, "C"); 466 } 467 468 } 469 470 // Extract date/time 471 SimpleDateFormat sdf = new java.text.SimpleDateFormat("yyMMdd/HHmmss"); 472 Date d = null; 473 474 try { 475 476 d = sdf.parse(csvLine[2] + "/" + csvLine[3]); 477 // format date according to GPX 478 SimpleDateFormat f = new SimpleDateFormat( 479 "yyyy-MM-dd'T'HH:mm:ss'Z'"); 480 481 wpt.attr.put(ColumbusCSVReader.TIME_TAG, f.format(d).toString()); 482 wpt.setTime(); 483 } catch (ParseException ex) { 484 dateConversionErrors++; 485 System.err.println(ex); 486 } 487 488 // Add further attributes 489 // Elevation height (altitude provided by GPS signal) 490 wpt.attr.put(ColumbusCSVReader.ELEVATIONHEIGHT_TAG, csvLine[6]); 491 492 // Add data of extended mode, if applicable 493 if (isExtMode && !ColumbusCSVPreferences.ignoreDOP()) { 494 addExtendedGPSData(csvLine, wpt); 495 } 496 497 return wpt; 498 } 499 500 /** 501 * Gets the full path of the audio file. Same as 502 * <code>getVoxFilePath(getWorkingDirOfImport(), voxFile)</code>. 503 * 504 * @param voxFile 505 * The name of the audio file without dir and extension. 506 * @return 507 * 508 */ 509 public File getVoxFilePath(String voxFile) { 510 return getVoxFilePath(getWorkingDirOfImport(), voxFile); 511 } 512 513 /** 514 * Gets the full path of the audio file. 515 * 516 * @param fileDir 517 * The directory containing the audio file. 518 * @param voxFile 519 * The name of the audio file without dir and extension. 520 * @return 521 */ 522 public File getVoxFilePath(String fileDir, String voxFile) { 523 // The FAT16 file name is interpreted differently from case-sensitive 524 // file systems, so we 525 // have to test several variants 526 String[] fileNameVariants = new String[] { voxFile, 527 voxFile.toLowerCase(), voxFile.toUpperCase() }; 528 529 for (int i = 0; i < fileNameVariants.length; i++) { 530 File file = new File(fileDir + File.separator + fileNameVariants[i]); 531 if (file.exists()) { 532 return file; 533 } 534 } 535 return null; // give up... 536 537 } 538 539 /** 540 * Adds extended GPS data (*DOP and fix mode) to the way point 541 * 542 * @param csvLine 543 * @param wpt 544 */ 545 private void addExtendedGPSData(String[] csvLine, WayPoint wpt) { 546 // Fix mode 547 wpt.attr.put(FIX_TAG, csvLine[9].toLowerCase()); 548 549 Float f; 550 // Position errors (dop = dilution of position) 551 f = ColumbusCSVUtils.floatFromString(csvLine[11]); 552 if (f != Float.NaN) { 553 wpt.attr.put(ColumbusCSVReader.PDOP_TAG, f); 554 } else { 555 dopConversionErrors++; 556 } 557 558 f = ColumbusCSVUtils.floatFromString(csvLine[12]); 559 if (f != Float.NaN) { 560 wpt.attr.put(ColumbusCSVReader.HDOP_TAG, f); 561 } else { 562 dopConversionErrors++; 563 } 564 565 f = ColumbusCSVUtils.floatFromString(csvLine[13]); 566 if (f != Float.NaN) { 567 wpt.attr.put(ColumbusCSVReader.VDOP_TAG, f); 568 } else { 569 dopConversionErrors++; 570 } 571 } 572 573 /** 574 * Adds a link to a way point. 575 * 576 * @param wpt 577 * The way point to add the link to. 578 * @param voxFile 579 * @param file 580 * @return True, if link has been added; otherwise false 581 */ 582 public boolean addLinkToWayPoint(WayPoint wpt, String voxFile, File file) { 583 if (file == null || wpt == null || voxFile == null) 584 return false; 585 586 GpxLink lnk = new GpxLink(file.toURI().toString()); 587 lnk.type = ColumbusCSVReader.AUDIO_WAV_LINK; 588 lnk.text = voxFile; 589 590 // JOSM expects a collection of links here... 591 Collection<GpxLink> linkList = new ArrayList<GpxLink>(1); 592 linkList.add(lnk); 593 594 wpt.attr.put(GpxData.META_LINKS, linkList); 595 wpt.attr.put(ColumbusCSVReader.COMMENT_TAG, "Audio recording"); 596 wpt.attr.put(ColumbusCSVReader.DESC_TAG, voxFile); 597 return true; 598 } 599 600 /** 601 * Splits a line of the CSV files into it's tokens. 602 * 603 * @param line 604 * @return Array containing the tokens of the CSV file. 605 */ 606 private static String[] getCSVLine(String line) { 607 if (line == null || line.length() == 0) 608 return EMPTY_LINE; 609 610 StringTokenizer st = new StringTokenizer(line, SEPS, false); 611 int n = st.countTokens(); 612 613 String[] res = new String[n]; 614 for (int i = 0; i < n; i++) { 615 res[i] = st.nextToken().trim(); 616 } 617 return res; 618 } 619 620 /** 621 * Extracts the number from a VOX file name, e. g. for a file named 622 * "VOX01524" this method will return 1524. 623 * 624 * @param fileName 625 * The vox file name. 626 * @return The number of the vox file or -1; if the given name was not 627 * valid. 628 */ 629 private int getNumberOfVoxfile(String fileName) { 630 if (fileName == null) 631 return -1; 632 633 try { 634 String num = fileName.substring(3); 635 int val = Integer.parseInt(num); 636 return val; 637 } catch (NumberFormatException e) { 638 return -1; 639 } 640 } 641 642 /** 643 * Return the number of date conversion errors. 644 * 645 * @return 646 */ 647 public int getNumberOfDateConversionErrors() { 648 return dateConversionErrors; 649 } 650 651 /** 652 * Return the number of pdop/vdop/hdop conversion errors. 653 * 654 * @return 655 */ 656 public int getNumberOfDOPConversionErrors() { 657 return dopConversionErrors; 658 } 659 660 /** 661 * Gets the number of first vox file. 662 * 663 * @return 664 */ 665 public int getFirstVoxNumber() { 666 return firstVoxNumber; 667 } 668 669 /** 670 * Gets the number of last vox file. 671 * 672 * @return 673 */ 674 public int getLastVoxNumber() { 675 return lastVoxNumber; 676 } 677 678 /** 679 * Gets the map containing the vox files with their associated way point. 680 * 681 * @return 682 */ 683 public HashMap<String, WayPoint> getVoxFileMap() { 684 return voxFiles; 685 } 686 687 /** 688 * Gets the list containing all imported track and way points. 689 * 690 * @return 691 */ 692 public List<WayPoint> getAllWayPoints() { 693 return allWpts; 694 } 695 696 /** 697 * Gets the import directory. 698 * 699 * @return 700 */ 701 public String getWorkingDirOfImport() { 702 return fileDir; 703 } 617 704 }
Note:
See TracChangeset
for help on using the changeset viewer.