Changeset 9741 in josm
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
r9727 r9741 35 35 import java.util.Hashtable; 36 36 import java.util.List; 37 import java.util.Objects; 37 38 import java.util.TimeZone; 38 39 import java.util.zip.GZIPInputStream; … … 94 95 95 96 private final transient GeoImageLayer yLayer; 96 private double timezone;97 private longdelta;97 private Timezone timezone; 98 private Offset delta; 98 99 99 100 /** … … 122 123 // Parse values again, to display an error if the format is not recognized 123 124 try { 124 timezone = parseTimezone(tfTimezone.getText().trim());125 timezone = Timezone.parseTimezone(tfTimezone.getText().trim()); 125 126 } catch (ParseException e) { 126 127 JOptionPane.showMessageDialog(Main.parent, e.getMessage(), … … 130 131 131 132 try { 132 delta = parseOffset(tfOffset.getText().trim());133 delta = Offset.parseOffset(tfOffset.getText().trim()); 133 134 } catch (ParseException e) { 134 135 JOptionPane.showMessageDialog(Main.parent, e.getMessage(), … … 168 169 break; 169 170 case DONE: 170 Main.pref.put("geoimage.timezone", formatTimezone(timezone));171 Main.pref.put("geoimage.delta", Long.toString(delta * 1000));171 Main.pref.put("geoimage.timezone", timezone.formatTimezone()); 172 Main.pref.put("geoimage.delta", delta.formatOffset()); 172 173 Main.pref.put("geoimage.showThumbs", yLayer.useThumbs); 173 174 … … 410 411 411 412 String tzDesc = new StringBuilder(tzStr).append(" (") 412 .append( formatTimezone(tz.getRawOffset() / 3600000.0))413 .append(new Timezone(tz.getRawOffset() / 3600000.0).formatTimezone()) 413 414 .append(')').toString(); 414 415 vtTimezones.add(tzDesc); … … 428 429 429 430 cbTimezones.setSelectedItem(new StringBuilder(defaultTz.getID()).append(" (") 430 .append( formatTimezone(defaultTz.getRawOffset() / 3600000.0))431 .append(new Timezone(defaultTz.getRawOffset() / 3600000.0).formatTimezone()) 431 432 .append(')').toString()); 432 433 … … 551 552 552 553 Main.pref.put("geoimage.timezoneid", tzId); 553 tfOffset.setText( Long.toString(delta / 1000));554 tfOffset.setText(Offset.milliseconds(delta).formatOffset()); 554 555 tfTimezone.setText(tzValue); 555 556 … … 609 610 } 610 611 try { 611 timezone = parseTimezone(prefTimezone);612 timezone = Timezone.parseTimezone(prefTimezone); 612 613 } catch (ParseException e) { 613 timezone = 0;614 timezone = Timezone.ZERO; 614 615 } 615 616 616 617 tfTimezone = new JosmTextField(10); 617 tfTimezone.setText( formatTimezone(timezone));618 tfTimezone.setText(timezone.formatTimezone()); 618 619 619 620 try { 620 delta = parseOffset(Main.pref.get("geoimage.delta", "0"));621 delta = Offset.parseOffset(Main.pref.get("geoimage.delta", "0")); 621 622 } catch (ParseException e) { 622 delta = 0; 623 } 624 delta = delta / 1000; // milliseconds -> seconds 623 delta = Offset.ZERO; 624 } 625 625 626 626 tfOffset = new JosmTextField(10); 627 tfOffset.setText( Long.toString(delta));627 tfOffset.setText(delta.formatOffset()); 628 628 629 629 JButton buttonViewGpsPhoto = new JButton(tr("<html>Use photo of an accurate clock,<br>" … … 813 813 private String statusText() { 814 814 try { 815 timezone = parseTimezone(tfTimezone.getText().trim());816 delta = parseOffset(tfOffset.getText().trim());815 timezone = Timezone.parseTimezone(tfTimezone.getText().trim()); 816 delta = Offset.parseOffset(tfOffset.getText().trim()); 817 817 } catch (ParseException e) { 818 818 return e.getMessage(); … … 839 839 return tr("No gpx selected"); 840 840 841 final long offset_ms = ((long) (timezone * 3600) + delta) * 1000; // in milliseconds841 final long offset_ms = ((long) (timezone.getHours() * 3600 * 1000)) + delta.getMilliseconds(); // in milliseconds 842 842 lastNumMatched = matchGpxTrack(dateImgLst, selGpx.data, offset_ms); 843 843 … … 869 869 public void actionPerformed(ActionEvent arg0) { 870 870 871 long diff = delta + Math.round(timezone*60*60);871 long diff = delta.getSeconds() + Math.round(timezone.getHours() * 60 * 60); 872 872 873 873 double diffInH = (double) diff/(60*60); // hours … … 934 934 935 935 try { 936 timezone = parseTimezone(zone);936 timezone = Timezone.parseTimezone(zone); 937 937 } catch (ParseException pe) { 938 938 throw new RuntimeException(pe); 939 939 } 940 delta = sldMinutes.getValue()*60 + sldSeconds.getValue();940 delta = Offset.seconds(sldMinutes.getValue() * 60 + sldSeconds.getValue() + 24 * 60 * 60L * dayOffset); // add the day offset 941 941 942 942 tfTimezone.getDocument().removeDocumentListener(statusBarUpdater); 943 943 tfOffset.getDocument().removeDocumentListener(statusBarUpdater); 944 944 945 tfTimezone.setText( formatTimezone(timezone));946 tfOffset.setText( Long.toString(delta + 24*60*60L*dayOffset)); // add the day offset to the offset field945 tfTimezone.setText(timezone.formatTimezone()); 946 tfOffset.setText(delta.formatOffset()); 947 947 948 948 tfTimezone.getDocument().addDocumentListener(statusBarUpdater); … … 1009 1009 * @param imgs the images to correlate 1010 1010 * @param gpx the gpx track to correlate to 1011 * @return a pair of timezone (in hours) and offset (in seconds)1011 * @return a pair of timezone and offset 1012 1012 * @throws IndexOutOfBoundsException when there are no images 1013 1013 * @throws NoGpxTimestamps when the gpx track does not contain a timestamp 1014 1014 */ 1015 static Pair< Double, Long> autoGuess(List<ImageEntry> imgs, GpxData gpx) throws IndexOutOfBoundsException, NoGpxTimestamps {1015 static Pair<Timezone, Offset> autoGuess(List<ImageEntry> imgs, GpxData gpx) throws IndexOutOfBoundsException, NoGpxTimestamps { 1016 1016 1017 1017 // Init variables … … 1056 1056 final double timezone = (double) Math.round(tz * 2) / 2; // hours, rounded to one decimal place 1057 1057 final long delta = Math.round(diff - timezone * 60 * 60); // seconds 1058 return Pair.create( timezone, delta);1058 return Pair.create(new Timezone(timezone), Offset.seconds(delta)); 1059 1059 } 1060 1060 … … 1071 1071 1072 1072 try { 1073 final Pair< Double, Long> r = autoGuess(imgs, gpx);1073 final Pair<Timezone, Offset> r = autoGuess(imgs, gpx); 1074 1074 timezone = r.a; 1075 1075 delta = r.b; … … 1089 1089 tfOffset.getDocument().removeDocumentListener(statusBarUpdater); 1090 1090 1091 tfTimezone.setText( formatTimezone(timezone));1092 tfOffset.setText( Long.toString(delta));1091 tfTimezone.setText(timezone.formatTimezone()); 1092 tfOffset.setText(delta.formatOffset()); 1093 1093 tfOffset.requestFocus(); 1094 1094 … … 1318 1318 } 1319 1319 1320 static String formatTimezone(double timezone) { 1321 StringBuilder ret = new StringBuilder(); 1322 1323 if (timezone < 0) { 1324 ret.append('-'); 1325 timezone = -timezone; 1326 } else { 1327 ret.append('+'); 1328 } 1329 ret.append((long) timezone).append(':'); 1330 int minutes = (int) ((timezone % 1) * 60); 1331 if (minutes < 10) { 1332 ret.append('0'); 1333 } 1334 ret.append(minutes); 1335 1336 return ret.toString(); 1337 } 1338 1339 static double parseTimezone(String timezone) throws ParseException { 1340 1341 if (timezone.isEmpty()) 1342 return 0; 1343 1344 String error = tr("Error while parsing timezone.\nExpected format: {0}", "+H:MM"); 1345 1346 char sgnTimezone = '+'; 1347 StringBuilder hTimezone = new StringBuilder(); 1348 StringBuilder mTimezone = new StringBuilder(); 1349 int state = 1; // 1=start/sign, 2=hours, 3=minutes. 1350 for (int i = 0; i < timezone.length(); i++) { 1351 char c = timezone.charAt(i); 1352 switch (c) { 1353 case ' ' : 1354 if (state != 2 || hTimezone.length() != 0) 1355 throw new ParseException(error, i); 1356 break; 1357 case '+' : 1358 case '-' : 1359 if (state == 1) { 1360 sgnTimezone = c; 1361 state = 2; 1362 } else 1363 throw new ParseException(error, i); 1364 break; 1365 case ':' : 1366 case '.' : 1367 if (state == 2) { 1368 state = 3; 1369 } else 1370 throw new ParseException(error, i); 1371 break; 1372 case '0' : case '1' : case '2' : case '3' : case '4' : 1373 case '5' : case '6' : case '7' : case '8' : case '9' : 1374 switch(state) { 1375 case 1 : 1376 case 2 : 1377 state = 2; 1378 hTimezone.append(c); 1379 break; 1380 case 3 : 1381 mTimezone.append(c); 1382 break; 1383 default : 1384 throw new ParseException(error, i); 1385 } 1386 break; 1387 default : 1388 throw new ParseException(error, i); 1389 } 1390 } 1391 1392 int h = 0; 1393 int m = 0; 1394 try { 1395 h = Integer.parseInt(hTimezone.toString()); 1396 if (mTimezone.length() > 0) { 1397 m = Integer.parseInt(mTimezone.toString()); 1398 } 1399 } catch (NumberFormatException nfe) { 1400 // Invalid timezone 1401 throw new ParseException(error, 0); 1402 } 1403 1404 if (h > 12 || m > 59) 1405 throw new ParseException(error, 0); 1406 else 1407 return (h + m / 60.0) * (sgnTimezone == '-' ? -1 : 1); 1408 } 1409 1410 static long parseOffset(String offset) throws ParseException { 1411 String error = tr("Error while parsing offset.\nExpected format: {0}", "number"); 1412 1413 if (!offset.isEmpty()) { 1320 static final class Timezone { 1321 1322 static final Timezone ZERO = new Timezone(0.0); 1323 private final double timezone; 1324 1325 Timezone(double hours) { 1326 this.timezone = hours; 1327 } 1328 1329 public double getHours() { 1330 return timezone; 1331 } 1332 1333 String formatTimezone() { 1334 StringBuilder ret = new StringBuilder(); 1335 1336 double timezone = this.timezone; 1337 if (timezone < 0) { 1338 ret.append('-'); 1339 timezone = -timezone; 1340 } else { 1341 ret.append('+'); 1342 } 1343 ret.append((long) timezone).append(':'); 1344 int minutes = (int) ((timezone % 1) * 60); 1345 if (minutes < 10) { 1346 ret.append('0'); 1347 } 1348 ret.append(minutes); 1349 1350 return ret.toString(); 1351 } 1352 1353 static Timezone parseTimezone(String timezone) throws ParseException { 1354 1355 if (timezone.isEmpty()) 1356 return ZERO; 1357 1358 String error = tr("Error while parsing timezone.\nExpected format: {0}", "+H:MM"); 1359 1360 char sgnTimezone = '+'; 1361 StringBuilder hTimezone = new StringBuilder(); 1362 StringBuilder mTimezone = new StringBuilder(); 1363 int state = 1; // 1=start/sign, 2=hours, 3=minutes. 1364 for (int i = 0; i < timezone.length(); i++) { 1365 char c = timezone.charAt(i); 1366 switch (c) { 1367 case ' ': 1368 if (state != 2 || hTimezone.length() != 0) 1369 throw new ParseException(error, i); 1370 break; 1371 case '+': 1372 case '-': 1373 if (state == 1) { 1374 sgnTimezone = c; 1375 state = 2; 1376 } else 1377 throw new ParseException(error, i); 1378 break; 1379 case ':': 1380 case '.': 1381 if (state == 2) { 1382 state = 3; 1383 } else 1384 throw new ParseException(error, i); 1385 break; 1386 case '0': 1387 case '1': 1388 case '2': 1389 case '3': 1390 case '4': 1391 case '5': 1392 case '6': 1393 case '7': 1394 case '8': 1395 case '9': 1396 switch (state) { 1397 case 1: 1398 case 2: 1399 state = 2; 1400 hTimezone.append(c); 1401 break; 1402 case 3: 1403 mTimezone.append(c); 1404 break; 1405 default: 1406 throw new ParseException(error, i); 1407 } 1408 break; 1409 default: 1410 throw new ParseException(error, i); 1411 } 1412 } 1413 1414 int h = 0; 1415 int m = 0; 1414 1416 try { 1415 if (offset.startsWith("+")) {1416 offset = offset.substring(1);1417 }1418 return Long.parseLong(offset);1417 h = Integer.parseInt(hTimezone.toString()); 1418 if (mTimezone.length() > 0) { 1419 m = Integer.parseInt(mTimezone.toString()); 1420 } 1419 1421 } catch (NumberFormatException nfe) { 1422 // Invalid timezone 1420 1423 throw new ParseException(error, 0); 1421 1424 } 1422 } else { 1423 return 0; 1425 1426 if (h > 12 || m > 59) 1427 throw new ParseException(error, 0); 1428 else 1429 return new Timezone((h + m / 60.0) * (sgnTimezone == '-' ? -1 : 1)); 1430 } 1431 1432 @Override 1433 public boolean equals(Object o) { 1434 if (this == o) return true; 1435 if (!(o instanceof Timezone)) return false; 1436 Timezone timezone1 = (Timezone) o; 1437 return Double.compare(timezone1.timezone, timezone) == 0; 1438 } 1439 1440 @Override 1441 public int hashCode() { 1442 return Objects.hash(timezone); 1443 } 1444 } 1445 1446 static final class Offset { 1447 1448 static final Offset ZERO = new Offset(0); 1449 private final long milliseconds; 1450 1451 private Offset(long milliseconds) { 1452 this.milliseconds = milliseconds; 1453 } 1454 1455 static Offset milliseconds(long milliseconds) { 1456 return new Offset(milliseconds); 1457 } 1458 1459 static Offset seconds(long seconds) { 1460 return new Offset(1000 * seconds); 1461 } 1462 1463 long getMilliseconds() { 1464 return milliseconds; 1465 } 1466 1467 long getSeconds() { 1468 return milliseconds / 1000; 1469 } 1470 1471 String formatOffset() { 1472 return Long.toString(milliseconds / 1000); 1473 } 1474 1475 static Offset parseOffset(String offset) throws ParseException { 1476 String error = tr("Error while parsing offset.\nExpected format: {0}", "number"); 1477 1478 if (!offset.isEmpty()) { 1479 try { 1480 if (offset.startsWith("+")) { 1481 offset = offset.substring(1); 1482 } 1483 return Offset.seconds(Long.parseLong(offset)); 1484 } catch (NumberFormatException nfe) { 1485 throw new ParseException(error, 0); 1486 } 1487 } else { 1488 return Offset.ZERO; 1489 } 1490 } 1491 1492 @Override 1493 public boolean equals(Object o) { 1494 if (this == o) return true; 1495 if (!(o instanceof Offset)) return false; 1496 Offset offset = (Offset) o; 1497 return milliseconds == offset.milliseconds; 1498 } 1499 1500 @Override 1501 public int hashCode() { 1502 return Objects.hash(milliseconds); 1424 1503 } 1425 1504 } -
trunk/test/unit/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImagesTest.java
r9727 r9741 73 73 i0.setExifTime(DateUtils.fromString("2016:01:03 11:59:54")); // 4 sec before start of GPX 74 74 i0.createTmp(); 75 assertEquals(Pair.create(0.0, -4L), CorrelateGpxWithImages.autoGuess(Collections.singletonList(i0), gpx)); 75 assertEquals(Pair.create(CorrelateGpxWithImages.Timezone.ZERO, CorrelateGpxWithImages.Offset.seconds(-4)), 76 CorrelateGpxWithImages.autoGuess(Collections.singletonList(i0), gpx)); 76 77 } 77 78 78 79 @Test 79 80 public void testFormatTimezone() throws Exception { 80 assertEquals("+1:00", CorrelateGpxWithImages.formatTimezone(1));81 assertEquals("+6:30", CorrelateGpxWithImages.formatTimezone(6.5));82 assertEquals("-6:30", CorrelateGpxWithImages.formatTimezone(-6.5));83 assertEquals("+3:08", CorrelateGpxWithImages.formatTimezone(Math.PI));84 assertEquals("+2:43", CorrelateGpxWithImages.formatTimezone(Math.E));81 assertEquals("+1:00", new CorrelateGpxWithImages.Timezone(1).formatTimezone()); 82 assertEquals("+6:30", new CorrelateGpxWithImages.Timezone(6.5).formatTimezone()); 83 assertEquals("-6:30", new CorrelateGpxWithImages.Timezone(-6.5).formatTimezone()); 84 assertEquals("+3:08", new CorrelateGpxWithImages.Timezone(Math.PI).formatTimezone()); 85 assertEquals("+2:43", new CorrelateGpxWithImages.Timezone(Math.E).formatTimezone()); 85 86 } 86 87 87 88 @Test 88 89 public void testParseTimezone() throws ParseException { 89 assertEquals(1, CorrelateGpxWithImages.parseTimezone("+01:00"), 1e-3); 90 assertEquals(1, CorrelateGpxWithImages.parseTimezone("+1:00"), 1e-3); 91 assertEquals(1.5, CorrelateGpxWithImages.parseTimezone("+01:30"), 1e-3); 92 assertEquals(11.5, CorrelateGpxWithImages.parseTimezone("+11:30"), 1e-3); 90 assertEquals(1, CorrelateGpxWithImages.Timezone.parseTimezone("+01:00").getHours(), 1e-3); 91 assertEquals(1, CorrelateGpxWithImages.Timezone.parseTimezone("+1:00").getHours(), 1e-3); 92 assertEquals(1.5, CorrelateGpxWithImages.Timezone.parseTimezone("+01:30").getHours(), 1e-3); 93 assertEquals(11.5, CorrelateGpxWithImages.Timezone.parseTimezone("+11:30").getHours(), 1e-3); 94 } 95 96 @Test 97 public void testFormatOffest() throws ParseException { 98 assertEquals("0", CorrelateGpxWithImages.Offset.seconds(0).formatOffset()); 99 assertEquals("123", CorrelateGpxWithImages.Offset.seconds(123).formatOffset()); 100 assertEquals("-4242", CorrelateGpxWithImages.Offset.seconds(-4242).formatOffset()); 93 101 } 94 102 95 103 @Test 96 104 public void testParseOffest() throws ParseException { 97 assertEquals(0, CorrelateGpxWithImages. parseOffset("0"));98 assertEquals(4242L, CorrelateGpxWithImages. parseOffset("4242"));99 assertEquals(-4242L, CorrelateGpxWithImages. parseOffset("-4242"));100 assertEquals(0L, CorrelateGpxWithImages. parseOffset("-0"));105 assertEquals(0, CorrelateGpxWithImages.Offset.parseOffset("0").getSeconds()); 106 assertEquals(4242L, CorrelateGpxWithImages.Offset.parseOffset("4242").getSeconds()); 107 assertEquals(-4242L, CorrelateGpxWithImages.Offset.parseOffset("-4242").getSeconds()); 108 assertEquals(0L, CorrelateGpxWithImages.Offset.parseOffset("-0").getSeconds()); 101 109 } 102 110 }
Note:
See TracChangeset
for help on using the changeset viewer.