]> gitweb.fperrin.net Git - GpsPrune.git/commitdiff
Version 10, May 2010
authoractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 14:35:04 +0000 (15:35 +0100)
committeractivityworkshop <mail@activityworkshop.net>
Sat, 14 Feb 2015 14:35:04 +0000 (15:35 +0100)
83 files changed:
tim/prune/App.java
tim/prune/FunctionLibrary.java
tim/prune/GpsPruner.java
tim/prune/I18nManager.java
tim/prune/config/Config.java
tim/prune/copyright.txt
tim/prune/data/Checker.java [new file with mode: 0644]
tim/prune/data/Coordinate.java
tim/prune/data/Track.java
tim/prune/data/TrackInfo.java
tim/prune/function/AboutScreen.java
tim/prune/function/AddMapSourceDialog.java [new file with mode: 0644]
tim/prune/function/DiskCacheConfig.java [new file with mode: 0644]
tim/prune/function/FullRangeDetails.java
tim/prune/function/MapSourceListModel.java [new file with mode: 0644]
tim/prune/function/PasteCoordinates.java
tim/prune/function/SetLanguage.java
tim/prune/function/SetMapBgFunction.java
tim/prune/function/SetPathsFunction.java
tim/prune/function/charts/Charter.java
tim/prune/function/srtm/LookupSrtmFunction.java [new file with mode: 0644]
tim/prune/function/srtm/SrtmTile.java [new file with mode: 0644]
tim/prune/function/srtm/TileFinder.java [new file with mode: 0644]
tim/prune/function/srtm/gen/GenerateTileLookup.java [new file with mode: 0644]
tim/prune/function/srtm/gen/tiles1.txt [new file with mode: 0644]
tim/prune/function/srtm/gen/tiles2.txt [new file with mode: 0644]
tim/prune/function/srtm/gen/tiles3.txt [new file with mode: 0644]
tim/prune/function/srtm/gen/tiles4.txt [new file with mode: 0644]
tim/prune/function/srtm/gen/tiles5.txt [new file with mode: 0644]
tim/prune/function/srtm/gen/tiles6.txt [new file with mode: 0644]
tim/prune/function/srtm/srtmtiles.dat [new file with mode: 0644]
tim/prune/gui/DetailsDisplay.java
tim/prune/gui/DisplayUtils.java
tim/prune/gui/GenericChart.java [deleted file]
tim/prune/gui/MenuManager.java
tim/prune/gui/PhotoThumbnail.java
tim/prune/gui/ProfileChart.java [deleted file]
tim/prune/gui/map/CloudmadeMapSource.java [new file with mode: 0644]
tim/prune/gui/map/DiskTileCacher.java [new file with mode: 0644]
tim/prune/gui/map/MapCanvas.java
tim/prune/gui/map/MapSource.java [new file with mode: 0644]
tim/prune/gui/map/MapSourceLibrary.java [new file with mode: 0644]
tim/prune/gui/map/MapTileCacher.java [deleted file]
tim/prune/gui/map/MapTileConfig.java [deleted file]
tim/prune/gui/map/MapTileManager.java [new file with mode: 0644]
tim/prune/gui/map/MemTileCacher.java [new file with mode: 0644]
tim/prune/gui/map/MffMapSource.java [new file with mode: 0644]
tim/prune/gui/map/OsmMapSource.java [new file with mode: 0644]
tim/prune/gui/profile/AltitudeData.java [new file with mode: 0644]
tim/prune/gui/profile/ProfileChart.java [new file with mode: 0644]
tim/prune/gui/profile/ProfileData.java [new file with mode: 0644]
tim/prune/gui/profile/SpeedData.java [new file with mode: 0644]
tim/prune/jpeg/ExifGateway.java [new file with mode: 0644]
tim/prune/jpeg/ExifLibrary.java [new file with mode: 0644]
tim/prune/jpeg/ExternalExifLibrary.java [new file with mode: 0644]
tim/prune/jpeg/InternalExifLibrary.java [new file with mode: 0644]
tim/prune/jpeg/JpegData.java [moved from tim/prune/drew/jpeg/JpegData.java with 70% similarity]
tim/prune/jpeg/drew/ExifReader.java [moved from tim/prune/drew/jpeg/ExifReader.java with 92% similarity]
tim/prune/jpeg/drew/JpegException.java [moved from tim/prune/drew/jpeg/JpegException.java with 93% similarity]
tim/prune/jpeg/drew/JpegSegmentData.java [moved from tim/prune/drew/jpeg/JpegSegmentData.java with 95% similarity]
tim/prune/jpeg/drew/JpegSegmentReader.java [moved from tim/prune/drew/jpeg/JpegSegmentReader.java with 96% similarity]
tim/prune/jpeg/drew/Rational.java [moved from tim/prune/drew/jpeg/Rational.java with 94% similarity]
tim/prune/lang/prune-texts_af.properties
tim/prune/lang/prune-texts_de.properties
tim/prune/lang/prune-texts_de_CH.properties
tim/prune/lang/prune-texts_en.properties
tim/prune/lang/prune-texts_es.properties
tim/prune/lang/prune-texts_fr.properties
tim/prune/lang/prune-texts_in.properties
tim/prune/lang/prune-texts_it.properties
tim/prune/lang/prune-texts_ja.properties
tim/prune/lang/prune-texts_pl.properties
tim/prune/lang/prune-texts_pt.properties
tim/prune/lang/prune-texts_ro.properties
tim/prune/lang/prune-texts_tr.properties
tim/prune/lang/prune-texts_zh.properties
tim/prune/load/JpegLoader.java
tim/prune/load/NmeaFileLoader.java
tim/prune/load/NmeaMessage.java
tim/prune/load/xml/ZipFileLoader.java
tim/prune/readme.txt
tim/prune/save/GpxCacher.java
tim/prune/undo/UndoLookupSrtm.java [new file with mode: 0644]

index ab9724b3bb90bd99de28f882a0ef4337bac39e42..07f68b1222e5dbc4b2214e94dfacc91405c8f896 100644 (file)
@@ -10,6 +10,7 @@ import javax.swing.JFrame;
 import javax.swing.JOptionPane;
 
 import tim.prune.data.Altitude;
+import tim.prune.data.Checker;
 import tim.prune.data.DataPoint;
 import tim.prune.data.Field;
 import tim.prune.data.LatLonRectangle;
@@ -578,14 +579,13 @@ public class App
        {
                // create undo object
                UndoCreatePoint undo = new UndoCreatePoint();
+               _undoStack.add(undo);
                // add point to track
                inPoint.setSegmentStart(true);
                _track.appendPoints(new DataPoint[] {inPoint});
                // ensure track's field list contains point's fields
                _track.extendFieldList(inPoint.getFieldList());
                _trackInfo.selectPoint(_trackInfo.getTrack().getNumPoints()-1);
-               // add undo object to stack
-               _undoStack.add(undo);
                // update listeners
                UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.createpoint"));
        }
@@ -647,8 +647,8 @@ public class App
         * @param inAltFormat altitude format
         * @param inSourceInfo information about the source of the data
         */
-       public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray, Altitude.Format inAltFormat,
-               SourceInfo inSourceInfo)
+       public void informDataLoaded(Field[] inFieldArray, Object[][] inDataArray,
+               Altitude.Format inAltFormat, SourceInfo inSourceInfo)
        {
                // Check whether loaded array can be properly parsed into a Track
                Track loadedTrack = new Track();
@@ -660,6 +660,11 @@ public class App
                        loadNextFile();
                        return;
                }
+               // Check for doubled track
+               if (Checker.isDoubledTrack(loadedTrack)) {
+                       JOptionPane.showMessageDialog(_frame, I18nManager.getText("dialog.open.contentsdoubled"),
+                               I18nManager.getText("function.open"), JOptionPane.WARNING_MESSAGE);
+               }
                // Decide whether to load or append
                if (_track.getNumPoints() > 0)
                {
@@ -716,7 +721,8 @@ public class App
                }
                UpdateMessageBroker.informSubscribers();
                // Update status bar
-               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile") + " '" + inSourceInfo.getName() + "'");
+               UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile")
+                       + " '" + inSourceInfo.getName() + "'");
                // update menu
                _menuManager.informFileLoaded();
                // load next file if there's a queue
index 0e642dd37a0348e9e91254ce54265eca6a616616..1f7bcfd2d8562091816c4984cfd01ae3b712584f 100644 (file)
@@ -7,6 +7,7 @@ import tim.prune.function.compress.CompressTrackFunction;
 import tim.prune.function.distance.DistanceFunction;
 import tim.prune.function.edit.PointNameEditor;
 import tim.prune.function.gpsies.GetGpsiesFunction;
+import tim.prune.function.srtm.LookupSrtmFunction;
 import tim.prune.load.GpsLoader;
 import tim.prune.save.GpsSaver;
 import tim.prune.save.GpxExporter;
@@ -28,6 +29,7 @@ public abstract class FunctionLibrary
        public static RearrangeWaypointsFunction FUNCTION_REARRANGE_WAYPOINTS = null;
        public static GenericFunction FUNCTION_REARRANGE_PHOTOS = null;
        public static GenericFunction FUNCTION_COMPRESS = null;
+       public static GenericFunction FUNCTION_LOOKUP_SRTM = null;
        public static GenericFunction FUNCTION_ADD_TIME_OFFSET  = null;
        public static GenericFunction FUNCTION_ADD_ALTITUDE_OFFSET  = null;
        public static GenericFunction FUNCTION_CONVERT_NAMES_TO_TIMES  = null;
@@ -44,6 +46,7 @@ public abstract class FunctionLibrary
        public static GenericFunction FUNCTION_FULL_RANGE_DETAILS = null;
        public static GenericFunction FUNCTION_GET_GPSIES = null;
        public static GenericFunction FUNCTION_SET_MAP_BG = null;
+       public static GenericFunction FUNCTION_SET_DISK_CACHE = null;
        public static GenericFunction FUNCTION_SET_PATHS  = null;
        public static GenericFunction FUNCTION_SET_KMZ_IMAGE_SIZE = null;
        public static GenericFunction FUNCTION_SET_COLOURS = null;
@@ -70,6 +73,7 @@ public abstract class FunctionLibrary
                FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp);
                FUNCTION_REARRANGE_PHOTOS = new RearrangePhotosFunction(inApp);
                FUNCTION_COMPRESS = new CompressTrackFunction(inApp);
+               FUNCTION_LOOKUP_SRTM = new LookupSrtmFunction(inApp);
                FUNCTION_ADD_TIME_OFFSET = new AddTimeOffset(inApp);
                FUNCTION_ADD_ALTITUDE_OFFSET = new AddAltitudeOffset(inApp);
                FUNCTION_CONVERT_NAMES_TO_TIMES = new ConvertNamesToTimes(inApp);
@@ -86,6 +90,7 @@ public abstract class FunctionLibrary
                FUNCTION_FULL_RANGE_DETAILS = new FullRangeDetails(inApp);
                FUNCTION_GET_GPSIES = new GetGpsiesFunction(inApp);
                FUNCTION_SET_MAP_BG = new SetMapBgFunction(inApp);
+               FUNCTION_SET_DISK_CACHE = new DiskCacheConfig(inApp);
                FUNCTION_SET_PATHS = new SetPathsFunction(inApp);
                FUNCTION_SET_KMZ_IMAGE_SIZE = new SetKmzImageSize(inApp);
                FUNCTION_SET_COLOURS = new SetColours(inApp);
index 7a172a4a64ceeb0a2576de987a4240b3018cc423..ac61501a2cadc025315918261f138fcc91f367ef 100644 (file)
@@ -17,11 +17,11 @@ import tim.prune.config.ConfigException;
 import tim.prune.gui.DetailsDisplay;
 import tim.prune.gui.IconManager;
 import tim.prune.gui.MenuManager;
-import tim.prune.gui.ProfileChart;
 import tim.prune.gui.SelectorDisplay;
 import tim.prune.gui.StatusBar;
 import tim.prune.gui.Viewport;
 import tim.prune.gui.map.MapCanvas;
+import tim.prune.gui.profile.ProfileChart;
 
 /**
  * Prune is a tool to visualize, edit, convert and prune GPS data
@@ -33,12 +33,15 @@ import tim.prune.gui.map.MapCanvas;
 public class GpsPruner
 {
        /** Version number of application, used in about screen and for version check */
-       public static final String VERSION_NUMBER = "9";
+       public static final String VERSION_NUMBER = "10";
        /** Build number, just used for about screen */
-       public static final String BUILD_NUMBER = "176";
+       public static final String BUILD_NUMBER = "189";
        /** Static reference to App object */
        private static App APP = null;
 
+       /** Program name, used for Frame title and for Macs also on the system bar */
+       private static final String PROGRAM_NAME = "Prune";
+
 
        /**
         * Main method
@@ -52,6 +55,13 @@ public class GpsPruner
                String configFilename = null;
                ArrayList<File> dataFiles = new ArrayList<File>();
                boolean showUsage = false;
+
+               // Mac OSX - specific properties (Mac insists that this is done as soon as possible)
+               if (System.getProperty("mrj.version") != null) {
+                       System.setProperty("apple.laf.useScreenMenuBar", "true"); // menu at top of screen
+                       System.setProperty("com.apple.mrj.application.apple.menu.about.name", PROGRAM_NAME);
+               }
+               // Loop over given arguments, if any
                for (int i=0; i<args.length; i++)
                {
                        String arg = args[i];
@@ -168,7 +178,8 @@ public class GpsPruner
         */
        private static void launch(ArrayList<File> inDataFiles)
        {
-               JFrame frame = new JFrame("Prune");
+               // Initialise Frame
+               JFrame frame = new JFrame(PROGRAM_NAME);
                APP = new App(frame);
 
                // make menu
index 143d7c884b418584d9ffba8a242dffb95e404b0e..349db3fcaff83bace412ebdf02e459b28d1e9199 100644 (file)
@@ -87,18 +87,18 @@ public abstract class I18nManager
        public static String getText(String inKey)
        {
                // look in external props file if available
-               if (ExternalPropsFile != null && ExternalPropsFile.containsKey(inKey))
+               if (ExternalPropsFile != null)
                {
-                       return ExternalPropsFile.getProperty(inKey);
+                       String extText = ExternalPropsFile.getProperty(inKey);
+                       if (extText != null) return extText;
                }
                // look in extra texts if available
                if (LocalTexts != null)
                {
                        try
                        {
-                               if (LocalTexts.containsKey(inKey)) {
-                                       return LocalTexts.getString(inKey);
-                               }
+                               String localText = LocalTexts.getString(inKey);
+                               if (localText != null) return localText;
                        }
                        catch (MissingResourceException mre) {}
                }
@@ -107,9 +107,8 @@ public abstract class I18nManager
                {
                        try
                        {
-                               if (EnglishTexts.containsKey(inKey)) {
-                                       return EnglishTexts.getString(inKey);
-                               }
+                               String engText = EnglishTexts.getString(inKey);
+                               if (engText != null) return engText;
                        }
                        catch (MissingResourceException mre) {}
                }
index a822b6e34ebef38da13b798f6afa7460c288f0eb..14231383fc03d860b4eea332575837e6cede4a0d 100644 (file)
@@ -37,12 +37,16 @@ public abstract class Config
        public static final String KEY_POVRAY_FONT = "prune.povrayfont";
        /** Key for metric/imperial */
        public static final String KEY_METRIC_UNITS = "prune.metricunits";
-       /** Key for map server index */
-       public static final String KEY_MAPSERVERINDEX = "prune.mapserverindex";
-       /** Key for map server url */
-       public static final String KEY_MAPSERVERURL = "prune.mapserverurl";
+       /** Key for index of map source */
+       public static final String KEY_MAPSOURCE_INDEX = "prune.mapsource";
+       /** Key for String containing custom map sources */
+       public static final String KEY_MAPSOURCE_LIST = "prune.mapsourcelist";
        /** Key for show map flag */
        public static final String KEY_SHOW_MAP = "prune.showmap";
+       /** Key for path to disk cache */
+       public static final String KEY_DISK_CACHE = "prune.diskcache";
+       /** Key for working online flag */
+       public static final String KEY_ONLINE_MODE = "prune.onlinemode";
        /** Key for width of thumbnails in kmz */
        public static final String KEY_KMZ_IMAGE_WIDTH = "prune.kmzimagewidth";
        /** Key for height of thumbnails in kmz */
@@ -217,7 +221,7 @@ public abstract class Config
        /**
         * Get the given configuration setting as a boolean
         * @param inKey key
-        * @return configuration setting as a boolean
+        * @return configuration setting as a boolean (default to true)
         */
        public static boolean getConfigBoolean(String inKey)
        {
index 7839745c74830dfeb92e4af7c369fe35d3eab1d1..a24ac608ab7c99cb329f8a6ad0a2ad3f57065fea 100644 (file)
@@ -1,8 +1,9 @@
 The source code of Prune is copyright 2006-2010 activityworkshop.net
 and distributed under the terms of the Gnu GPL version 2.
 
-The package drew.jpeg is taken from Drew Noakes' "Metadata extractor"
-which is copyright Drew Noakes 2002-2006 and was placed in the public domain.
+Portions of the package jpeg.drew (if included in this package) were taken
+from Drew Noakes' "Metadata extractor" v2.3.1 which is
+copyright Drew Noakes 2002-2006 and was placed in the public domain.
 
 Translations are copyright various contributors, some of whom are named
 in the source code and some preferred to remain anonymous.
\ No newline at end of file
diff --git a/tim/prune/data/Checker.java b/tim/prune/data/Checker.java
new file mode 100644 (file)
index 0000000..274c3e7
--- /dev/null
@@ -0,0 +1,68 @@
+package tim.prune.data;
+
+/**
+ * Class to provide checking functions
+ */
+public abstract class Checker
+{
+
+       /**
+        * Check if a given track is doubled, so that each point is given twice,
+        * once as waypoint and again as track point
+        * @param inTrack track to check
+        * @return true if track is doubled, false otherwise
+        */
+       public static boolean isDoubledTrack(Track inTrack)
+       {
+               // Check for empty track
+               if (inTrack == null || inTrack.getNumPoints() < 2) {return false;}
+               // Check for non-even number of points
+               final int numPoints = inTrack.getNumPoints();
+               if (numPoints % 2 == 1) {return false;}
+               // Loop through first half of track
+               final int halfNum = numPoints / 2;
+               for (int i=0; i<halfNum; i++)
+               {
+                       DataPoint firstPoint = inTrack.getPoint(i);
+                       DataPoint secondPoint = inTrack.getPoint(i + halfNum);
+                       if (!firstPoint.getLatitude().equals(secondPoint.getLatitude())
+                               || !firstPoint.getLongitude().equals(secondPoint.getLongitude())) {
+                               return false;
+                       }
+               }
+               // Passed the test, so contents must all be doubled
+               return true;
+       }
+
+       /**
+        * Find the index of the next segment start after the given index
+        * @param inTrack track object
+        * @param inIndex current index
+        * @return index of next segment start
+        */
+       public static int getNextSegmentStart(Track inTrack, int inIndex)
+       {
+               int i = inIndex + 1;
+               DataPoint point = null;
+               while ((point=inTrack.getPoint(i)) != null && !point.getSegmentStart()) {
+                       i++;
+               }
+               return Math.min(i, inTrack.getNumPoints()-1);
+       }
+
+       /**
+        * Find the index of the previous segment start before the given index
+        * @param inTrack track object
+        * @param inIndex current index
+        * @return index of previous segment start
+        */
+       public static int getPreviousSegmentStart(Track inTrack, int inIndex)
+       {
+               int i = inIndex - 1;
+               DataPoint point = null;
+               while ((point=inTrack.getPoint(i)) != null && !point.getSegmentStart()) {
+                       i--;
+               }
+               return Math.max(i, 0);
+       }
+}
index 190c66573b13e2c251a434407bc02315d34c0984..44ab779ab6c1a0d66f1254c3df6fb82391a955fb 100644 (file)
@@ -117,6 +117,7 @@ public abstract class Coordinate
                        }
                        // parse fields according to number found
                        _degrees = (int) fields[0];
+                       _asDouble = _degrees;
                        _originalFormat = hasCardinal?FORMAT_DEG:FORMAT_DEG_WITHOUT_CARDINAL;
                        _fracDenom = 10;
                        if (numFields == 2)
index d33886ea3f22eb2eee5057cba3bbd6a2cd9a8524..83ac9547f3ede67149ee5a1d0cce85758d45adae 100644 (file)
@@ -748,11 +748,14 @@ public class Track
        }
 
        /**
-        * @return true if track has altitude data (which are not all zero)
+        * @return true if track has altitude data
         */
        public boolean hasAltitudeData()
        {
-               return getAltitudeRange().getMaximum() > 0;
+               for (int i=0; i<_numPoints; i++) {
+                       if (_dataPoints[i].hasAltitude()) {return true;}
+               }
+               return false;
        }
 
        /**
index 254de9341e6119d098ef327196cefdfa0b20a7fa..6fa8e90b2e54ba39186053fcc38a1433d5ec298c 100644 (file)
@@ -399,7 +399,9 @@ public class TrackInfo
        {
                // See whether to start selection from current range start or current point
                int rangeStart = _selection.getStart();
-               if (rangeStart < 0) {rangeStart = _selection.getCurrentPointIndex();}
+               if (rangeStart < 0 || _selection.getCurrentPointIndex() != _selection.getEnd()) {
+                       rangeStart = _selection.getCurrentPointIndex();
+               }
                selectPoint(inPointNum);
                if (rangeStart < inPointNum) {
                        _selection.selectRange(rangeStart, inPointNum);
index 3c97a6d79c21e52ac1c7adc430d7999a6a7167f7..e0334b583ead9ff891aabb13a2f4edac69a4c091 100644 (file)
@@ -11,7 +11,12 @@ import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyEvent;
 import java.awt.event.KeyListener;
+import java.io.ByteArrayOutputStream;
+import java.io.File;
+import java.io.FileInputStream;
+import java.io.IOException;
 import java.io.InputStream;
+import java.util.zip.GZIPInputStream;
 
 import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
@@ -29,6 +34,7 @@ import tim.prune.ExternalTools;
 import tim.prune.GenericFunction;
 import tim.prune.GpsPruner;
 import tim.prune.I18nManager;
+import tim.prune.jpeg.ExifGateway;
 import tim.prune.threedee.WindowFactory;
 
 /**
@@ -144,6 +150,13 @@ public class AboutScreen extends GenericFunction
                        new JLabel(I18nManager.getText("dialog.about.systeminfo.gnuplot") + " : "),
                        0, 5);
                addToGridBagPanel(sysInfoPanel, gridBag, constraints, _installedLabels[3], 1, 5);
+               // Exif library
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints,
+                       new JLabel(I18nManager.getText("dialog.about.systeminfo.exiflib") + " : "),
+                       0, 6);
+               final String exiflibkey = "dialog.about.systeminfo.exiflib." + ExifGateway.getDescriptionKey();
+               addToGridBagPanel(sysInfoPanel, gridBag, constraints,
+                       new JLabel(I18nManager.getText(exiflibkey)), 1, 6);
                _tabs.add(I18nManager.getText("dialog.about.systeminfo"), sysInfoPanel);
 
                // Third pane for credits
@@ -178,32 +191,35 @@ public class AboutScreen extends GenericFunction
                        new JLabel("Ramon, Miguel, In\u00E9s, Piotr, Petrovsk, Josatoc, Weehal,"),
                        1, 3);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
-                       new JLabel(" theYinYeti, Rothermographer, Sam, Rudolph, nazotoko, katpatuka"),
+                       new JLabel(" theYinYeti, Rothermographer, Sam, Rudolph, nazotoko,"),
                        1, 4);
+               addToGridBagPanel(creditsPanel, gridBag, constraints,
+                       new JLabel(" katpatuka, R\u00E9mi"),
+                       1, 5);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.translations") + " : "),
-                       0, 5);
+                       0, 6);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel("Open Office, Gpsdrive, Babelfish, Leo, Launchpad"),
-                       1, 5);
+                       1, 6);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.devtools") + " : "),
-                       0, 6);
+                       0, 7);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel("Debian Linux, Sun Java, Eclipse, Svn, Gimp, Inkscape"),
-                       1, 6);
+                       1, 7);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.othertools") + " : "),
-                       0, 7);
+                       0, 8);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel("Openstreetmap, Povray, Exiftool, Google Earth, Gpsbabel, Gnuplot"),
-                       1, 7);
+                       1, 8);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel(I18nManager.getText("dialog.about.credits.thanks") + " : "),
-                       0, 8);
+                       0, 9);
                addToGridBagPanel(creditsPanel, gridBag, constraints,
                        new JLabel("Friends and loved ones, for encouragement and support"),
-                       1, 8);
+                       1, 9);
                _tabs.add(I18nManager.getText("dialog.about.credits"), creditsPanel);
 
                // Read me
@@ -271,6 +287,9 @@ public class AboutScreen extends GenericFunction
         */
        private String getReadmeText()
        {
+               // First, try locally-held readme.txt if available (as it normally should be)
+               // Readme file can either be in file system or packed in the same jar as code
+               String errorMessage = null;
                try
                {
                        // For some reason using ../readme.txt doesn't work, so need absolute path
@@ -278,11 +297,39 @@ public class AboutScreen extends GenericFunction
                        if (in != null) {
                                byte[] buffer = new byte[in.available()];
                                in.read(buffer);
+                               in.close();
                                return new String(buffer);
                        }
                }
-               catch (java.io.IOException e) {
-                       System.err.println("Exception trying to get readme : " + e.getMessage());
+               catch (IOException e) {
+                       errorMessage =  e.getMessage();
+               }
+               // Locally-held file failed, so try to find gz file installed on system (eg Debian)
+               try
+               {
+                       File gzFile = new File("/usr/share/doc/gpsprune/readme.txt.gz");
+                       if (gzFile.exists())
+                       {
+                               // Copy decompressed bytes from gz file into out
+                               InputStream in = new GZIPInputStream(new FileInputStream(gzFile));
+                               ByteArrayOutputStream out = new ByteArrayOutputStream();
+                               byte[] buffer = new byte[8 * 1024];
+                               int count = 0;
+                               do {
+                                       out.write(buffer, 0, count);
+                                       count = in.read(buffer, 0, buffer.length);
+                               } while (count != -1);
+                               out.close();
+                               in.close();
+                               return out.toString();
+                       }
+               }
+               catch (IOException e) {
+                       System.err.println("Exception trying to get readme.gz : " + e.getMessage());
+               }
+               // Only show first error message if couldn't get readme from gz either
+               if (errorMessage != null) {
+                       System.err.println("Exception trying to get readme: " + errorMessage);
                }
                return I18nManager.getText("error.readme.notfound");
        }
diff --git a/tim/prune/function/AddMapSourceDialog.java b/tim/prune/function/AddMapSourceDialog.java
new file mode 100644 (file)
index 0000000..d7126ea
--- /dev/null
@@ -0,0 +1,309 @@
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.CardLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.GridLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import javax.swing.BorderFactory;
+import javax.swing.ButtonGroup;
+import javax.swing.JButton;
+import javax.swing.JComboBox;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JRadioButton;
+import javax.swing.JTextField;
+
+import tim.prune.I18nManager;
+import tim.prune.gui.map.CloudmadeMapSource;
+import tim.prune.gui.map.MapSource;
+import tim.prune.gui.map.MapSourceLibrary;
+import tim.prune.gui.map.OsmMapSource;
+
+/**
+ * Class to handle the adding of a new map source
+ */
+public class AddMapSourceDialog
+{
+       private SetMapBgFunction _parent = null;
+       private JDialog _addDialog = null;
+       private JRadioButton[] _typeRadios = null;
+       private JPanel _cards = null;
+       // controls for osm panel
+       private JTextField _oNameField = null;
+       private JTextField _baseUrlField = null, _topUrlField = null;
+       private JComboBox _oZoomCombo = null;
+       // controls for cloudmade panel
+       private JTextField _cNameField = null;
+       private JTextField _cStyleField = null;
+       private JComboBox _cZoomCombo = null;
+       private JButton _okButton = null;
+
+
+       /**
+        * Constructor
+        * @param inParent parent dialog
+        */
+       public AddMapSourceDialog(JDialog inParentDialog, SetMapBgFunction inParentFunction)
+       {
+               _parent = inParentFunction;
+               _addDialog = new JDialog(inParentDialog, I18nManager.getText("dialog.addmapsource.title"), true);
+               _addDialog.add(makeDialogComponents());
+               _addDialog.setLocationRelativeTo(inParentDialog);
+               _addDialog.pack();
+       }
+
+
+       /**
+        * Create dialog components
+        * @return Panel containing all gui elements in dialog
+        */
+       private Component makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout());
+               // Top panel with two radio buttons to select source type
+               JPanel radioPanel = new JPanel();
+               ButtonGroup radioGroup = new ButtonGroup();
+               radioPanel.setLayout(new GridLayout(1, 0));
+               _typeRadios = new JRadioButton[2];
+               _typeRadios[0] = new JRadioButton("Openstreetmap");
+               radioGroup.add(_typeRadios[0]);
+               radioPanel.add(_typeRadios[0]);
+               _typeRadios[1] = new JRadioButton("Cloudmade");
+               radioGroup.add(_typeRadios[1]);
+               radioPanel.add(_typeRadios[1]);
+               _typeRadios[0].setSelected(true);
+               // listener for clicks on type radios
+               ActionListener typeListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               CardLayout cl = (CardLayout) _cards.getLayout();
+                               if (_typeRadios[0].isSelected()) {cl.first(_cards);}
+                               else {cl.last(_cards);}
+                               enableOK();
+                       }
+               };
+               _typeRadios[0].addActionListener(typeListener);
+               _typeRadios[1].addActionListener(typeListener);
+               radioPanel.setBorder(BorderFactory.createEmptyBorder(5, 5, 5, 5));
+               dialogPanel.add(radioPanel, BorderLayout.NORTH);
+
+               _cards = new JPanel();
+               _cards.setLayout(new CardLayout());
+               // listener
+               KeyAdapter keyListener = new KeyAdapter() {
+                       public void keyReleased(KeyEvent e) {
+                               super.keyReleased(e);
+                               enableOK();
+                       }
+               };
+               // openstreetmap panel
+               JPanel osmPanel = new JPanel();
+               osmPanel.setLayout(new GridLayout(0, 2, 5, 5));
+               osmPanel.setBorder(BorderFactory.createEmptyBorder(6, 2, 4, 2));
+               osmPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.sourcename")));
+               _oNameField = new JTextField(18);
+               _oNameField.addKeyListener(keyListener);
+               osmPanel.add(_oNameField);
+               // Base layer
+               osmPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.layer1url")));
+               _baseUrlField = new JTextField(18);
+               _baseUrlField.addKeyListener(keyListener);
+               osmPanel.add(_baseUrlField);
+               // Top layer
+               osmPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.layer2url")));
+               _topUrlField = new JTextField(18);
+               _topUrlField.addKeyListener(keyListener);
+               osmPanel.add(_topUrlField);
+               // Max zoom
+               osmPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.maxzoom")));
+               _oZoomCombo = new JComboBox();
+               for (int i=10; i<=20; i++) {
+                       _oZoomCombo.addItem("" + i);
+               }
+               osmPanel.add(_oZoomCombo);
+               _cards.add(osmPanel, "card1");
+               // Panel for cloudmade source
+               JPanel cloudPanel = new JPanel();
+               cloudPanel.setLayout(new GridLayout(0, 2, 5, 5));
+               cloudPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.sourcename")));
+               _cNameField = new JTextField(18);
+               _cNameField.addKeyListener(keyListener);
+               cloudPanel.add(_cNameField);
+               cloudPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.cloudstyle")));
+               _cStyleField = new JTextField(18);
+               _cStyleField.addKeyListener(keyListener);
+               cloudPanel.add(_cStyleField);
+               cloudPanel.add(new JLabel(I18nManager.getText("dialog.addmapsource.maxzoom")));
+               _cZoomCombo = new JComboBox();
+               for (int i=10; i<=20; i++) {
+                       _cZoomCombo.addItem("" + i);
+               }
+               cloudPanel.add(_cZoomCombo);
+               cloudPanel.add(new JLabel(" ")); // force four rows to space text boxes properly
+               _cards.add(cloudPanel, "card2");
+               // cards
+               JPanel holderPanel = new JPanel();
+               holderPanel.setLayout(new BorderLayout());
+               holderPanel.add(_cards, BorderLayout.NORTH);
+               dialogPanel.add(holderPanel, BorderLayout.CENTER);
+
+               // button panel at bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
+               ActionListener okListener = new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               finish();
+                       }
+               };
+               _okButton.addActionListener(okListener);
+               buttonPanel.add(_okButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _addDialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return dialogPanel;
+       }
+
+
+       /**
+        * Init and show the dialog
+        */
+       public void showDialog()
+       {
+               _oNameField.setText("");
+               _baseUrlField.setText("");
+               _topUrlField.setText("");
+               _oZoomCombo.setSelectedIndex(8);
+               _cNameField.setText("");
+               _cStyleField.setText("");
+               _cZoomCombo.setSelectedIndex(8);
+               _okButton.setEnabled(false);
+               _addDialog.setVisible(true);
+       }
+
+
+       /**
+        * Check the currently entered details and enable the OK button if it looks OK
+        */
+       private void enableOK()
+       {
+               boolean ok = false;
+               if (_typeRadios[0].isSelected()) {ok = isOsmPanelOk();}
+               if (_typeRadios[1].isSelected()) {ok = isCloudPanelOk();}
+               _okButton.setEnabled(ok);
+       }
+
+       /**
+        * Check the openstreetmap panel if all details are complete
+        * @return true if details look ok
+        */
+       private boolean isOsmPanelOk()
+       {
+               boolean ok = _oNameField.getText().trim().length() > 1;
+               URL baseUrl = null, topUrl = null;
+               try {
+                       // Try to parse base url if given
+                       String baseText = _baseUrlField.getText().trim();
+                       if (baseText.length() > 10) {
+                               baseUrl = new URL(baseText);
+                       }
+                       else if (baseText.length() > 0) {ok = false;}
+                       // Same again for top url if given
+                       String topText = _topUrlField.getText().trim();
+                       if (topText.length() > 10) {
+                               topUrl = new URL(topText);
+                       }
+                       else if (topText.length() > 0) {ok = false;}
+               } catch (MalformedURLException e) {
+                       ok = false;
+               }
+               // looks ok if at least one url given
+               return (ok && (baseUrl != null || topUrl != null));
+       }
+
+       /**
+        * Check the cloudmade panel if all details are complete
+        * @return true if details look ok
+        */
+       private boolean isCloudPanelOk()
+       {
+               boolean ok = _cNameField.getText().trim().length() > 1;
+               int styleNum = 0;
+               try {
+                       styleNum = Integer.parseInt(_cStyleField.getText());
+               }
+               catch (NumberFormatException nfe) {}
+               return (ok && styleNum > 0);
+       }
+
+       /**
+        * Finish by adding the requested source and refreshing the parent
+        */
+       private void finish()
+       {
+               MapSource newSource = null;
+               if (_typeRadios[0].isSelected())
+               {
+                       // Openstreetmap source
+                       String sourceName = getUniqueSourcename(_oNameField.getText());
+                       String url1 = _baseUrlField.getText().trim();
+                       String url2 = _topUrlField.getText().trim();
+                       newSource = new OsmMapSource(sourceName, url1, url2, _oZoomCombo.getSelectedIndex()+10);
+               }
+               else if (_typeRadios[1].isSelected())
+               {
+                       String sourceName = getUniqueSourcename(_cNameField.getText());
+                       newSource = new CloudmadeMapSource(sourceName, _cStyleField.getText(),
+                               _cZoomCombo.getSelectedIndex()+10);
+               }
+               // Add new source if ok
+               if (newSource != null)
+               {
+                       MapSourceLibrary.addSource(newSource);
+                       // inform setmapbg dialog
+                       _parent.updateList();
+                       _addDialog.setVisible(false);
+               }
+       }
+
+       /**
+        * Check the given source name if it exists in library already
+        * @param inName name to check
+        * @return unique name not yet in library
+        */
+       private static String getUniqueSourcename(String inName)
+       {
+               String name = inName;
+               if (name == null) {name = "";}
+               else {name = name.trim();}
+               if (name.equals("")) {
+                       name = I18nManager.getText("dialog.addmapsource.noname");
+               }
+               // Check there isn't already a map source with this name
+               if (MapSourceLibrary.hasSourceName(name))
+               {
+                       int suffix = 1;
+                       while (MapSourceLibrary.hasSourceName(name + suffix)) {
+                               suffix++;
+                       }
+                       name += suffix;
+               }
+               return name;
+       }
+}
diff --git a/tim/prune/function/DiskCacheConfig.java b/tim/prune/function/DiskCacheConfig.java
new file mode 100644 (file)
index 0000000..58643d1
--- /dev/null
@@ -0,0 +1,212 @@
+package tim.prune.function;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.KeyAdapter;
+import java.awt.event.KeyEvent;
+import java.io.File;
+
+import javax.swing.JButton;
+import javax.swing.JCheckBox;
+import javax.swing.JDialog;
+import javax.swing.JFileChooser;
+import javax.swing.JLabel;
+import javax.swing.JOptionPane;
+import javax.swing.JPanel;
+import javax.swing.JTextField;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.config.Config;
+
+/**
+ * Class to show the popup window for setting the path to disk cache
+ */
+public class DiskCacheConfig extends GenericFunction
+{
+       private JDialog _dialog = null;
+       private JCheckBox _cacheCheckbox = null;
+       private JTextField _cacheDirBox = null;
+       private JButton _browseButton = null;
+       private JButton _okButton = null;
+       private boolean _initialCheckState = false;
+       private String _initialCacheDir = null;
+
+       /**
+        * Constructor
+        * @param inApp app object
+        */
+       public DiskCacheConfig(App inApp)
+       {
+               super(inApp);
+       }
+
+       /**
+        * Return the name key for this function
+        */
+       public String getNameKey()
+       {
+               return "function.diskcache";
+       }
+
+       /**
+        * @return the contents of the window as a Component
+        */
+       private Component makeContents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout(0, 5));
+               // top panel
+               JPanel topPanel = new JPanel();
+               _cacheCheckbox = new JCheckBox(I18nManager.getText("dialog.diskcache.save"));
+               _cacheCheckbox.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               enableOk();
+                       }
+               });
+               topPanel.add(_cacheCheckbox);
+               dialogPanel.add(topPanel, BorderLayout.NORTH);
+               // dir panel
+               JPanel dirPanel = new JPanel();
+               dirPanel.setLayout(new BorderLayout());
+               dirPanel.add(new JLabel(I18nManager.getText("dialog.diskcache.dir")), BorderLayout.WEST);
+               _cacheDirBox = new JTextField(24);
+               _cacheDirBox.addKeyListener(new KeyAdapter() {
+                       public void keyReleased(KeyEvent arg0) {
+                               super.keyReleased(arg0);
+                               enableOk();
+                       }
+               });
+               dirPanel.add(_cacheDirBox, BorderLayout.CENTER);
+               _browseButton = new JButton(I18nManager.getText("button.browse"));
+               _browseButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               chooseDir();
+                       }
+               });
+               dirPanel.add(_browseButton, BorderLayout.EAST);
+               dialogPanel.add(dirPanel, BorderLayout.CENTER);
+
+               // Cancel button at the bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               _okButton = new JButton(I18nManager.getText("button.ok"));
+               _okButton.addActionListener(new ActionListener()
+               {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               finish();
+                       }
+               });
+               buttonPanel.add(_okButton);
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               _dialog.dispose();
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return dialogPanel;
+       }
+
+       /**
+        * Enable or disable the ok button according to what's changed
+        */
+       private void enableOk()
+       {
+               boolean checkState = _cacheCheckbox.isSelected();
+               _cacheDirBox.setEditable(checkState);
+               _browseButton.setEnabled(checkState);
+               boolean ok = false;
+               // If checkbox has stayed off then disable ok
+               if (!_initialCheckState && !checkState) {ok = false;}
+               else {
+                       // If checkbox has been switched off then enable
+                       if (!checkState) {ok = true;}
+                       else {
+                               // checkbox is on, check value
+                               String path = _cacheDirBox.getText();
+                               if (path.equals("") || (_initialCacheDir != null && path.equals(_initialCacheDir))) {
+                                       // Value blank or same as before
+                                       ok = false;
+                               }
+                               else {
+                                       ok = true;
+                               }
+                       }
+               }
+               _okButton.setEnabled(ok);
+       }
+
+       /**
+        * Show window
+        */
+       public void begin()
+       {
+               if (_dialog == null)
+               {
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()));
+                       _dialog.setLocationRelativeTo(_parentFrame);
+                       _dialog.getContentPane().add(makeContents());
+                       _dialog.pack();
+               }
+               // Set controls according to current config
+               String currPath = Config.getConfigString(Config.KEY_DISK_CACHE);
+               _cacheCheckbox.setSelected(currPath != null);
+               _cacheDirBox.setText(currPath==null?"":currPath);
+               enableOk();
+               // Remember current state
+               _initialCheckState = _cacheCheckbox.isSelected();
+               _dialog.setVisible(true);
+       }
+
+       /**
+        * Function activated by the "Browse..." button to select a directory for the cache
+        */
+       private void chooseDir()
+       {
+               JFileChooser chooser = new JFileChooser();
+               chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY);
+               // Set start path from currently selected dir
+               String path = _cacheDirBox.getText();
+               if (path.length() > 1) {chooser.setCurrentDirectory(new File(path));}
+               if (chooser.showOpenDialog(_parentFrame) == JFileChooser.APPROVE_OPTION)
+               {
+                       _cacheDirBox.setText(chooser.getSelectedFile().getAbsolutePath());
+               }
+               enableOk();
+       }
+
+       /**
+        * OK pressed, save selected settings in Config
+        */
+       private void finish()
+       {
+               String cachePath = (_cacheCheckbox.isSelected()?_cacheDirBox.getText():null);
+               // Create dir if it doesn't exist already and creation confirmed
+               if (cachePath != null)
+               {
+                       File cacheDir = new File(cachePath);
+                       if ((!cacheDir.exists() || !cacheDir.isDirectory()) && (JOptionPane.showConfirmDialog(_dialog,
+                               I18nManager.getText("dialog.diskcache.createdir") + ": " + cacheDir.getAbsolutePath() + " ?",
+                               I18nManager.getText(getNameKey()), JOptionPane.OK_CANCEL_OPTION) == JOptionPane.CANCEL_OPTION || !cacheDir.mkdir()))
+                       {
+                               JOptionPane.showMessageDialog(_dialog, I18nManager.getText("dialog.diskcache.nocreate"),
+                                       I18nManager.getText(getNameKey()), JOptionPane.WARNING_MESSAGE);
+                               return;
+                       }
+               }
+               Config.setConfigString(Config.KEY_DISK_CACHE, cachePath);
+               // inform subscribers so that tiles are wiped from memory and refetched
+               UpdateMessageBroker.informSubscribers(DataSubscriber.MAPSERVER_CHANGED);
+               _dialog.dispose();
+       }
+}
index ed86ef90ec54e75e7da713bd87f6424e8f051d66..338bf0bebbe1e1aef4d0130cf9b5d904b9c1a5c5 100644 (file)
@@ -22,6 +22,7 @@ import tim.prune.data.Altitude;
 import tim.prune.data.Distance;
 import tim.prune.data.Selection;
 import tim.prune.gui.DisplayUtils;
+import tim.prune.gui.profile.SpeedData;
 
 /**
  * Class to show the full range details in a separate popup
@@ -38,6 +39,7 @@ public class FullRangeDetails extends GenericFunction
        private JLabel _gradientLabel = null;
        /** Moving distance, speed */
        private JLabel _movingDistanceLabel = null, _aveMovingSpeedLabel = null;
+       private JLabel _maxSpeedLabel = null;
        /** Number formatter for one decimal place */
        private static final NumberFormat FORMAT_ONE_DP = NumberFormat.getNumberInstance();
        /** Flexible number formatter for different decimal places */
@@ -123,6 +125,12 @@ public class FullRangeDetails extends GenericFunction
                midPanel.add(movingSpeedLabel);
                _aveMovingSpeedLabel = new JLabel("5 km/h");
                midPanel.add(_aveMovingSpeedLabel);
+               // Maximum speed
+               JLabel maxSpeedLabel = new JLabel(I18nManager.getText("details.range.maxspeed") + ": ");
+               maxSpeedLabel.setHorizontalAlignment(JLabel.RIGHT);
+               midPanel.add(maxSpeedLabel);
+               _maxSpeedLabel = new JLabel("10 km/h");
+               midPanel.add(_maxSpeedLabel);
 
                dialogPanel.add(midPanel, BorderLayout.CENTER);
                // button panel at bottom
@@ -194,6 +202,22 @@ public class FullRangeDetails extends GenericFunction
                else {
                        _aveMovingSpeedLabel.setText("");
                }
+
+               // Maximum speed
+               SpeedData speeds = new SpeedData(_app.getTrackInfo().getTrack());
+               speeds.init();
+               double maxSpeed = 0.0;
+               for (int i=selection.getStart(); i<=selection.getEnd(); i++) {
+                       if (speeds.hasData(i) && (speeds.getData(i) > maxSpeed)) {
+                               maxSpeed = speeds.getData(i);
+                       }
+               }
+               if (maxSpeed > 0.0) {
+                       _maxSpeedLabel.setText(roundedNumber(maxSpeed) + " " + speedUnitsStr);
+               }
+               else {
+                       _maxSpeedLabel.setText("");
+               }
        }
 
        /**
diff --git a/tim/prune/function/MapSourceListModel.java b/tim/prune/function/MapSourceListModel.java
new file mode 100644 (file)
index 0000000..4548cc4
--- /dev/null
@@ -0,0 +1,47 @@
+package tim.prune.function;
+
+import javax.swing.AbstractListModel;
+
+import tim.prune.gui.map.MapSource;
+import tim.prune.gui.map.MapSourceLibrary;
+
+/**
+ * Class to act as list model for the map source list
+ */
+public class MapSourceListModel extends AbstractListModel
+{
+       /**
+        * @see javax.swing.ListModel#getSize()
+        */
+       public int getSize()
+       {
+               return MapSourceLibrary.getNumSources();
+       }
+
+       /**
+        * @see javax.swing.ListModel#getElementAt(int)
+        */
+       public Object getElementAt(int inIndex)
+       {
+               if (inIndex < 0 || inIndex >= getSize()) return "";
+               return MapSourceLibrary.getSource(inIndex).getName();
+       }
+
+       /**
+        * @param inIndex index in list
+        * @return corresponding map source object
+        */
+       public MapSource getSource(int inIndex)
+       {
+               if (inIndex < 0 || inIndex >= getSize()) return null;
+               return MapSourceLibrary.getSource(inIndex);
+       }
+
+       /**
+        * Fire event to notify that contents have changed
+        */
+       public void fireChanged()
+       {
+               this.fireContentsChanged(this, 0, getSize()-1);
+       }
+}
index 1106001ad3f10abaec76c3b17a73f24d4ac543fd..23fe8d285afd8af965a47e62f3fcdc0827a12603 100644 (file)
@@ -8,6 +8,7 @@ import java.awt.event.ActionListener;
 import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 import java.awt.event.MouseAdapter;
+import java.awt.event.MouseEvent;
 
 import javax.swing.BorderFactory;
 import javax.swing.JButton;
@@ -96,12 +97,15 @@ public class PasteCoordinates extends GenericFunction
                // Listeners to enable/disable ok button
                KeyAdapter keyListener = new KeyAdapter() {
                        /** Key released */
-                       public void keyReleased(KeyEvent arg0) {
+                       public void keyReleased(KeyEvent inE) {
                                enableOK();
+                               if (inE.getKeyCode() == KeyEvent.VK_ESCAPE) {
+                                       _dialog.dispose();
+                               }
                        }
                };
                MouseAdapter mouseListener = new MouseAdapter() {
-                       public void mouseReleased(java.awt.event.MouseEvent arg0) {
+                       public void mouseReleased(MouseEvent inE) {
                                enableOK();
                        };
                };
@@ -132,7 +136,7 @@ public class PasteCoordinates extends GenericFunction
                ActionListener okListener = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               finish();
+                               if (_okButton.isEnabled()) {finish();}
                        }
                };
                _okButton.addActionListener(okListener);
@@ -159,7 +163,7 @@ public class PasteCoordinates extends GenericFunction
        private void enableOK()
        {
                String text = _coordField.getText();
-               _okButton.setEnabled(text != null && text.length() > 10
+               _okButton.setEnabled(text != null && text.length() > 6
                        && (text.indexOf(' ') >= 0 || text.indexOf(',') >= 0));
        }
 
index d54e1be2cdef26eab604ce3358e059a3d839d22e..77fb091b3f939ccfbd78e7ef722b93cc5d476880 100644 (file)
@@ -43,11 +43,12 @@ public class SetLanguage extends GenericFunction
        /** Names of languages for display in dropdown (not translated) */
        private static final String[] LANGUAGE_NAMES = {"deutsch", "english", "espa\u00F1ol", "fran\u00E7ais",
                "italiano", "polski", "\u4e2d\u6587 (chinese)", "\u65E5\u672C\u8A9E (japanese)",
-               "schwiizerd\u00FC\u00FCtsch", "t\u00FCrk\u00E7e", "portugu\u00EAs", "bahasa indonesia", "rom\u00E2n\u0103"
+               "schwiizerd\u00FC\u00FCtsch", "t\u00FCrk\u00E7e", "portugu\u00EAs",
+               "afrikaans", "bahasa indonesia", "rom\u00E2n\u0103"
        };
        /** Associated language codes (must be in same order as names!) */
        private static final String[] LANGUAGE_CODES = {"de", "en", "es", "fr", "it", "pl", "zh", "ja",
-               "de_ch", "tr", "pt", "in", "ro"
+               "de_ch", "tr", "pt", "af", "in", "ro"
        };
 
 
index cadacf9962274010d0a4505c52bcc0f9fc739b3d..fb715b03b0b51f0f3d450bf4d4fa3ed91243b4cf 100644 (file)
@@ -2,20 +2,24 @@ package tim.prune.function;
 
 import java.awt.BorderLayout;
 import java.awt.Component;
+import java.awt.Dimension;
 import java.awt.FlowLayout;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
 import java.awt.event.KeyAdapter;
 import java.awt.event.KeyEvent;
 
+import javax.swing.BorderFactory;
 import javax.swing.BoxLayout;
-import javax.swing.ButtonGroup;
 import javax.swing.JButton;
 import javax.swing.JDialog;
 import javax.swing.JLabel;
+import javax.swing.JList;
 import javax.swing.JPanel;
-import javax.swing.JRadioButton;
-import javax.swing.JTextField;
+import javax.swing.JScrollPane;
+import javax.swing.ListSelectionModel;
+import javax.swing.event.ListSelectionEvent;
+import javax.swing.event.ListSelectionListener;
 
 import tim.prune.App;
 import tim.prune.DataSubscriber;
@@ -23,6 +27,7 @@ import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.config.Config;
+import tim.prune.gui.map.MapSourceLibrary;
 
 /**
  * Function to set the tile server for the map backgrounds
@@ -30,11 +35,13 @@ import tim.prune.config.Config;
 public class SetMapBgFunction extends GenericFunction
 {
        private JDialog _dialog = null;
+       private JList _list = null;
+       private MapSourceListModel _listModel = null;
+       private String _initialSource = null;
        private JButton _okButton = null;
-       private JRadioButton[] _serverRadios = null;
-       private JTextField _serverUrl = null;
-       /** Index of 'other' server with freeform url */
-       private static final int OTHER_SERVER_NUM = 3;
+       private JButton _deleteButton = null;
+       // Add dialog
+       private AddMapSourceDialog _addDialog = null;
 
 
        /**
@@ -63,10 +70,10 @@ public class SetMapBgFunction extends GenericFunction
                        _dialog.setLocationRelativeTo(_parentFrame);
                        _dialog.setDefaultCloseOperation(JDialog.DISPOSE_ON_CLOSE);
                        _dialog.getContentPane().add(makeDialogComponents());
-                       initValues();
                        _dialog.pack();
                }
-               enableOK();
+               initValues();
+               enableButtons();
                _dialog.setVisible(true);
        }
 
@@ -78,39 +85,48 @@ public class SetMapBgFunction extends GenericFunction
        private Component makeDialogComponents()
        {
                JPanel dialogPanel = new JPanel();
-               dialogPanel.setLayout(new BorderLayout());
-               // Main panel
-               JPanel mainPanel = new JPanel();
-               mainPanel.setLayout(new BoxLayout(mainPanel, BoxLayout.Y_AXIS));
-               _serverRadios = new JRadioButton[4];
-               ButtonGroup serverRadioGroup = new ButtonGroup();
-               String[] serverKeys = {"dialog.setmapbg.mapnik", "dialog.setmapbg.osma",
-                       "dialog.setmapbg.cyclemap", "dialog.setmapbg.other"};
-               // action listener for radios
-               ActionListener changeListener = new ActionListener() {
-                       public void actionPerformed(ActionEvent arg0) {
-                               enableOK();
+               dialogPanel.setLayout(new BorderLayout(8, 8));
+               // intro label
+               JLabel introLabel = new JLabel(I18nManager.getText("dialog.setmapbg.intro"));
+               introLabel.setBorder(BorderFactory.createEmptyBorder(5, 4, 1, 4));
+               dialogPanel.add(introLabel, BorderLayout.NORTH);
+               // list box
+               _listModel = new MapSourceListModel();
+               _list = new JList(_listModel);
+               _list.setSelectionMode(ListSelectionModel.SINGLE_SELECTION);
+               dialogPanel.add(new JScrollPane(_list), BorderLayout.CENTER);
+               _list.addListSelectionListener(new ListSelectionListener() {
+                       public void valueChanged(ListSelectionEvent arg0) {
+                               enableButtons();
                        }
-               };
-               // Create four radio buttons
-               for (int i=0; i<4; i++)
-               {
-                       _serverRadios[i] = new JRadioButton(I18nManager.getText(serverKeys[i]));
-                       _serverRadios[i].addActionListener(changeListener);
-                       serverRadioGroup.add(_serverRadios[i]);
-                       mainPanel.add(_serverRadios[i]);
-               }
-               // entry field for other server urls
-               mainPanel.add(new JLabel(I18nManager.getText("dialog.setmapbg.server")));
-               _serverUrl = new JTextField("", 12);
-               _serverUrl.addKeyListener(new KeyAdapter() {
+               });
+               _list.addKeyListener(new KeyAdapter() {
                        public void keyReleased(KeyEvent e) {
                                super.keyReleased(e);
-                               enableOK();
+                               if (e.getKeyCode() == KeyEvent.VK_ESCAPE) {
+                                       _dialog.dispose();
+                               }
                        }
                });
-               mainPanel.add(_serverUrl);
-               dialogPanel.add(mainPanel, BorderLayout.NORTH);
+               _list.setPreferredSize(new Dimension(200, 200));
+               // button panel on right
+               JPanel rightPanel = new JPanel();
+               rightPanel.setLayout(new BoxLayout(rightPanel, BoxLayout.Y_AXIS));
+               JButton addButton = new JButton(I18nManager.getText("button.addnew"));
+               addButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               addNewSource();
+                       }
+               });
+               rightPanel.add(addButton);
+               _deleteButton = new JButton(I18nManager.getText("button.delete"));
+               _deleteButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent arg0) {
+                               deleteMapSource(_list.getSelectedIndex());
+                       }
+               });
+               rightPanel.add(_deleteButton);
+               dialogPanel.add(rightPanel, BorderLayout.EAST);
 
                // button panel at bottom
                JPanel buttonPanel = new JPanel();
@@ -142,49 +158,65 @@ public class SetMapBgFunction extends GenericFunction
         */
        private void initValues()
        {
-               // Get values from config
-               try {
-                       _serverRadios[Config.getConfigInt(Config.KEY_MAPSERVERINDEX)].setSelected(true);
-               }
-               catch (ArrayIndexOutOfBoundsException e) {} // ignore
-               String url = Config.getConfigString(Config.KEY_MAPSERVERURL);
-               if (url != null) {_serverUrl.setText(url);}
-               // Choose default if none selected
-               if (getSelectedServer() < 0) {
-                       _serverRadios[0].setSelected(true);
+               updateList();
+               // Get selected value from config
+               int currSource = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
+               if (currSource < 0 || currSource >= _listModel.getSize()) {
+                       currSource = 0;
                }
+               _initialSource = _listModel.getSource(currSource).getSiteStrings();
+               _list.setSelectedIndex(currSource);
        }
 
        /**
-        * @return index of selected radio button, or -1 if none
+        * @return index of selected server, or -1 if none
         */
        private int getSelectedServer()
        {
-               // Loop over all four radios
-               for (int i=0; i<4; i++) {
-                       if (_serverRadios[i].isSelected()) {return i;}
-               }
-               // None selected
-               return -1;
+               return _list.getSelectedIndex();
        }
 
        /**
-        * Enable or disable the OK button according to the selection
+        * Enable or disable the buttons according to the selection
         */
-       private void enableOK()
+       private void enableButtons()
        {
                int serverNum = getSelectedServer();
-               _okButton.setEnabled(inputOK());
-               _serverUrl.setEnabled(serverNum == OTHER_SERVER_NUM);
+               _okButton.setEnabled(serverNum >= 0 && serverNum < _listModel.getSize()
+                       && !_listModel.getSource(serverNum).getSiteStrings().equals(_initialSource));
+               _deleteButton.setEnabled(serverNum >= MapSourceLibrary.getNumFixedSources()
+                       && serverNum < _listModel.getSize());
        }
 
        /**
-        * @return true if inputs are ok
+        * Start the dialog to add a new map source to the list
         */
-       private boolean inputOK()
+       private void addNewSource()
        {
-               int serverNum = getSelectedServer();
-               return serverNum >= 0 && (serverNum != OTHER_SERVER_NUM || _serverUrl.getText().length() > 4);
+               if (_addDialog == null) {
+                       _addDialog = new AddMapSourceDialog(_dialog, this);
+               }
+               _addDialog.showDialog();
+       }
+
+       /**
+        * Delete the selected map source so it is no longer available
+        * @param inIndex index within list
+        */
+       private void deleteMapSource(int inIndex)
+       {
+               MapSourceLibrary.deleteSource(inIndex);
+               updateList();
+               enableButtons();
+       }
+
+       /**
+        * use the library to update the current list, after add or delete
+        */
+       public void updateList()
+       {
+               _listModel.fireChanged();
+               Config.setConfigString(Config.KEY_MAPSOURCE_LIST, MapSourceLibrary.getConfigString());
        }
 
        /**
@@ -193,9 +225,8 @@ public class SetMapBgFunction extends GenericFunction
        private void finish()
        {
                int serverNum = getSelectedServer();
-               if (!inputOK()) {serverNum = 0;}
-               Config.setConfigInt(Config.KEY_MAPSERVERINDEX, serverNum);
-               Config.setConfigString(Config.KEY_MAPSERVERURL, _serverUrl.getText());
+               if (serverNum < 0) {serverNum = 0;}
+               Config.setConfigInt(Config.KEY_MAPSOURCE_INDEX, serverNum);
                UpdateMessageBroker.informSubscribers(DataSubscriber.MAPSERVER_CHANGED);
                _dialog.dispose();
        }
index 3ded22310994a6850a033423fb3d546f979db4d1..a5131af7f8aa960b56c3bcc108f795c857cbc0ac 100644 (file)
@@ -87,7 +87,10 @@ public class SetPathsFunction extends GenericFunction
 
                // Main panel with edit boxes for paths
                JPanel mainPanel = new JPanel();
-               mainPanel.setLayout(new GridLayout(3, 3, 10, 1));
+               mainPanel.setLayout(new GridLayout(NUM_KEYS+1, 3, 10, 1));
+               mainPanel.add(new JLabel(" "));
+               mainPanel.add(new JLabel(" "));
+               mainPanel.add(new JLabel(I18nManager.getText("dialog.setpaths.found")));
                _editFields = new JTextField[NUM_KEYS];
                _installedLabels = new JLabel[NUM_KEYS];
                for (int i=0; i<NUM_KEYS; i++)
@@ -147,7 +150,7 @@ public class SetPathsFunction extends GenericFunction
                for (int i=0; i<NUM_KEYS; i++)
                {
                        String command = _editFields[i].getText();
-                       _installedLabels[i].setText(ExternalTools.isToolInstalled(i, command)?yesText:noText);
+                       _installedLabels[i].setText("   " + (ExternalTools.isToolInstalled(i, command)?yesText:noText));
                }
        }
 
index 4b3fd370ee9c6866d6280236127c5a94881914b8..3edb4753aceabdd648b9b0a6254c6a5351f33132 100644 (file)
@@ -189,14 +189,6 @@ public class Charter extends GenericFunction
                // button panel on bottom
                JPanel buttonPanel = new JPanel();
                buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
-               // Cancel button
-               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
-               cancelButton.addActionListener(new ActionListener() {
-                       public void actionPerformed(ActionEvent e) {
-                               _dialog.setVisible(false);
-                       }
-               });
-               buttonPanel.add(cancelButton);
                // ok button
                JButton okButton = new JButton(I18nManager.getText("button.ok"));
                okButton.addActionListener(new ActionListener() {
@@ -206,6 +198,14 @@ public class Charter extends GenericFunction
                        }
                });
                buttonPanel.add(okButton);
+               // Cancel button
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               _dialog.setVisible(false);
+                       }
+               });
+               buttonPanel.add(cancelButton);
                dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
                return dialogPanel;
        }
@@ -526,6 +526,7 @@ public class Charter extends GenericFunction
                ChartSeries values = new ChartSeries(inTrack.getNumPoints());
                DataPoint prevPoint = null, currPoint = null, nextPoint = null;
                DataPoint[] points = getDataPoints(inTrack, false);
+               final boolean useMetric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
                // Loop over collected points
                for (int i=1; i<(points.length-1); i++)
                {
@@ -541,7 +542,7 @@ public class Charter extends GenericFunction
                                        + DataPoint.calculateRadiansBetween(currPoint, nextPoint);
                                double time = nextPoint.getTimestamp().getSecondsSince(prevPoint.getTimestamp()) / 60.0 / 60.0;
                                // Convert to distance and pass to chartseries
-                               if (Config.getConfigBoolean(Config.KEY_METRIC_UNITS)) {
+                               if (useMetric) {
                                        values.setData(i, Distance.convertRadiansToDistance(rads, Units.KILOMETRES) / time);
                                } else {
                                        values.setData(i, Distance.convertRadiansToDistance(rads, Units.MILES) / time);
diff --git a/tim/prune/function/srtm/LookupSrtmFunction.java b/tim/prune/function/srtm/LookupSrtmFunction.java
new file mode 100644 (file)
index 0000000..30183d2
--- /dev/null
@@ -0,0 +1,282 @@
+package tim.prune.function.srtm;
+
+import java.awt.BorderLayout;
+import java.awt.Component;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.io.IOException;
+import java.net.URL;
+import java.util.ArrayList;
+import java.util.zip.ZipEntry;
+import java.util.zip.ZipInputStream;
+
+import javax.swing.JButton;
+import javax.swing.JDialog;
+import javax.swing.JLabel;
+import javax.swing.JPanel;
+import javax.swing.JProgressBar;
+
+import tim.prune.App;
+import tim.prune.DataSubscriber;
+import tim.prune.GenericFunction;
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.Track;
+import tim.prune.undo.UndoLookupSrtm;
+
+/**
+ * Class to provide a lookup function for point altitudes
+ * using the Space Shuttle's SRTM data files.
+ * HGT files are downloaded into memory via HTTP and point altitudes
+ * can then be interpolated from the 3m grid data.
+ */
+public class LookupSrtmFunction extends GenericFunction implements Runnable
+{
+       /** function dialog */
+       private JDialog _dialog = null;
+       /** Progress bar for function */
+       private JProgressBar _progressBar = null;
+       /** Cancel flag */
+       private boolean _cancelled = false;
+
+       /** Expected size of hgt file in bytes */
+       private static final long HGT_SIZE = 2884802L;
+       /** Altitude below which is considered void */
+       private static final int VOID_VAL = -32768;
+
+       /**
+        * Constructor
+        * @param inApp App object
+        */
+       public LookupSrtmFunction(App inApp)
+       {
+               super(inApp);
+       }
+
+       /** @return name key */
+       public String getNameKey() {
+               return "function.lookupsrtm";
+       }
+
+       /**
+        * Begin the lookup
+        */
+       public void begin()
+       {
+               if (_dialog == null)
+               {
+                       _dialog = new JDialog(_parentFrame, I18nManager.getText(getNameKey()), false);
+                       _dialog.setLocationRelativeTo(_parentFrame);
+                       _dialog.getContentPane().add(makeDialogComponents());
+                       _dialog.pack();
+               }
+               _progressBar.setMinimum(0);
+               _progressBar.setMaximum(100);
+               _progressBar.setValue(20);
+               _cancelled = false;
+               // start new thread for time-consuming part
+               new Thread(this).start();
+       }
+
+
+       /**
+        * Make the dialog components
+        * @return the GUI components for the dialog
+        */
+       private Component makeDialogComponents()
+       {
+               JPanel dialogPanel = new JPanel();
+               dialogPanel.setLayout(new BorderLayout());
+               dialogPanel.add(new JLabel(I18nManager.getText("confirm.running")), BorderLayout.NORTH);
+               _progressBar = new JProgressBar();
+               _progressBar.setPreferredSize(new Dimension(250, 30));
+               dialogPanel.add(_progressBar, BorderLayout.CENTER);
+               // Cancel button at the bottom
+               JPanel buttonPanel = new JPanel();
+               buttonPanel.setLayout(new FlowLayout(FlowLayout.RIGHT));
+               JButton cancelButton = new JButton(I18nManager.getText("button.cancel"));
+               cancelButton.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               _cancelled = true;
+                       }
+               });
+               buttonPanel.add(cancelButton);
+               dialogPanel.add(buttonPanel, BorderLayout.SOUTH);
+               return dialogPanel;
+       }
+
+       /**
+        * Run method using separate thread
+        */
+       public void run()
+       {
+               _dialog.setVisible(true);
+               // Compile list of tiles to get
+               Track track = _app.getTrackInfo().getTrack();
+               ArrayList<SrtmTile> tileList = new ArrayList<SrtmTile>();
+               for (int i=0; i<track.getNumPoints(); i++)
+               {
+                       // Only consider points which don't have altitudes already
+                       if (!track.getPoint(i).hasAltitude())
+                       {
+                               SrtmTile tile = new SrtmTile(track.getPoint(i));
+                               boolean alreadyGot = false;
+                               for (int t=0; t<tileList.size(); t++) {
+                                       if (tileList.get(t).equals(tile)) {
+                                               alreadyGot = true;
+                                       }
+                               }
+                               if (!alreadyGot) {tileList.add(tile);}
+                       }
+               }
+               UndoLookupSrtm undo = new UndoLookupSrtm(_app.getTrackInfo());
+               int numAltitudesFound = 0;
+               // Update progress bar
+               _progressBar.setMaximum(tileList.size());
+               _progressBar.setIndeterminate(tileList.size() <= 1);
+               _progressBar.setValue(0);
+               // Get urls for each tile
+               URL[] urls = TileFinder.getUrls(tileList);
+               for (int t=0; t<tileList.size() && !_cancelled; t++)
+               {
+                       if (urls[t] != null)
+                       {
+                               SrtmTile tile = tileList.get(t);
+                               // System.out.println("tile " + t + " of " + tileList.size() + " = " + urls[t].toString());
+                               try {
+                                       _progressBar.setValue(t);
+                                       final int ARRLENGTH = 1201*1201;
+                                       int[] heights = new int[ARRLENGTH];
+                                       // Open zipinputstream on url and check size
+                                       ZipInputStream inStream = new ZipInputStream(urls[t].openStream());
+                                       ZipEntry entry = inStream.getNextEntry();
+                                       boolean entryOk = (entry.getSize() == HGT_SIZE);
+                                       if (entryOk)
+                                       {
+                                               // Read entire file contents into one byte array
+                                               for (int i=0; i<ARRLENGTH; i++) {
+                                                       heights[i] = inStream.read()*256 + inStream.read();
+                                                       if (heights[i] >= 32768) {heights[i] -= 65536;}
+                                               }
+                                       }
+                                       //else {
+                                       //      System.out.println("length not ok: " + entry.getSize());
+                                       //}
+                                       // Close stream from url
+                                       inStream.close();
+
+                                       if (entryOk)
+                                       {
+                                               // Loop over all points in track, try to apply altitude from array
+                                               for (int p=0; p<track.getNumPoints(); p++)
+                                               {
+                                                       DataPoint point = track.getPoint(p);
+                                                       if (!point.hasAltitude() || point.getAltitude().getValue() == 0) {
+                                                               if (new SrtmTile(point).equals(tile))
+                                                               {
+                                                                       double x = (point.getLongitude().getDouble() - tile.getLongitude()) * 1200;
+                                                                       double y = 1201 - (point.getLatitude().getDouble() - tile.getLatitude()) * 1200;
+                                                                       int idx1 = ((int)y)*1201 + (int)x;
+                                                                       try {
+                                                                               int[] fouralts = {heights[idx1], heights[idx1+1], heights[idx1-1201], heights[idx1-1200]};
+                                                                               int numVoids = (fouralts[0]==VOID_VAL?1:0) + (fouralts[1]==VOID_VAL?1:0)
+                                                                                       + (fouralts[2]==VOID_VAL?1:0) + (fouralts[3]==VOID_VAL?1:0);
+                                                                               // if (numVoids > 0) System.out.println(numVoids + " voids found");
+                                                                               double altitude = 0.0;
+                                                                               switch (numVoids) {
+                                                                                       case 0: altitude = bilinearInterpolate(fouralts, x, y); break;
+                                                                                       case 1: altitude = bilinearInterpolate(fixVoid(fouralts), x, y); break;
+                                                                                       case 2:
+                                                                                       case 3: altitude = averageNonVoid(fouralts); break;
+                                                                                       default: altitude = VOID_VAL;
+                                                                               }
+                                                                               if (altitude != VOID_VAL) {
+                                                                                       point.setFieldValue(Field.ALTITUDE, ""+altitude, false);
+                                                                                       numAltitudesFound++;
+                                                                               }
+                                                                       }
+                                                                       catch (ArrayIndexOutOfBoundsException obe) {
+                                                                               //System.err.println("lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1);
+                                                                       }
+                                                               }
+                                                       }
+                                               }
+                                       }
+                               }
+                               catch (IOException ioe) {
+                                       //System.err.println("eek - " + ioe.getMessage());
+                               }
+                       }
+               }
+               _dialog.dispose();
+               if (numAltitudesFound > 0)
+               {
+                       // Inform app including undo information
+                       track.requestRescale();
+                       UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_ADDED_OR_REMOVED);
+                       _app.completeFunction(undo, I18nManager.getText("confirm.lookupsrtm1") + " " + numAltitudesFound
+                               + " " + I18nManager.getText("confirm.lookupsrtm2"));
+               }
+               else {
+                       _app.showErrorMessage(getNameKey(), "error.lookupsrtm.none");
+               }
+       }
+
+       /**
+        * Perform a bilinear interpolation on the given altitude array
+        * @param inAltitudes array of four altitude values on corners of square (bl, br, tl, tr)
+        * @param inX x coordinate
+        * @param inY y coordinate
+        * @return interpolated altitude
+        */
+       private static double bilinearInterpolate(int[] inAltitudes, double inX, double inY)
+       {
+               double alpha = inX - (int) inX;
+               double beta  = 1 - (inY - (int) inY);
+               double alt = (1-alpha)*(1-beta)*inAltitudes[0] + alpha*(1-beta)*inAltitudes[1]
+                       + (1-alpha)*beta*inAltitudes[2] + alpha*beta*inAltitudes[3];
+               return alt;
+       }
+
+       /**
+        * Fix a single void in the given array by replacing it with the average of the others
+        * @param inAltitudes array of altitudes containing one void
+        * @return fixed array without voids
+        */
+       private static int[] fixVoid(int[] inAltitudes)
+       {
+               int[] fixed = new int[inAltitudes.length];
+               for (int i=0; i<inAltitudes.length; i++) {
+                       if (inAltitudes[i] == VOID_VAL) {
+                               fixed[i] = (int) Math.round(averageNonVoid(inAltitudes));
+                       }
+                       else {
+                               fixed[i] = inAltitudes[i];
+                       }
+               }
+               return fixed;
+       }
+
+       /**
+        * Calculate the average of the non-void altitudes in the given array
+        * @param inAltitudes array of altitudes with one or more voids
+        * @return average of non-void altitudes
+        */
+       private static final double averageNonVoid(int[] inAltitudes)
+       {
+               double totalAltitude = 0.0;
+               int numAlts = 0;
+               for (int i=0; i<inAltitudes.length; i++) {
+                       if (inAltitudes[i] != VOID_VAL) {
+                               totalAltitude += inAltitudes[i];
+                               numAlts++;
+                       }
+               }
+               if (numAlts < 1) {return VOID_VAL;}
+               return totalAltitude / numAlts;
+       }
+}
diff --git a/tim/prune/function/srtm/SrtmTile.java b/tim/prune/function/srtm/SrtmTile.java
new file mode 100644 (file)
index 0000000..d7ab38f
--- /dev/null
@@ -0,0 +1,62 @@
+package tim.prune.function.srtm;
+
+import tim.prune.data.Coordinate;
+import tim.prune.data.DataPoint;
+
+/**
+ * Class to represent a single tile of Srtm data, from a single hgt.zip file
+ */
+public class SrtmTile
+{
+       /** Latitude in degrees north/south */
+       private int _latitude = 0;
+       /** Longitude ini degrees east/west */
+       private int _longitude = 0;
+
+       /**
+        * Constructor working out the tile for a single point
+        * @param inPoint data point
+        */
+       public SrtmTile(DataPoint inPoint)
+       {
+               Coordinate latitude = inPoint.getLatitude();
+               _latitude = (int) Math.floor(latitude.getDouble());
+               Coordinate longitude = inPoint.getLongitude();
+               _longitude = (int) Math.floor(longitude.getDouble());
+       }
+
+       /**
+        * Check for equality
+        * @param inOther other tile object
+        * @return true if both represent same tile
+        */
+       public boolean equals(SrtmTile inOther)
+       {
+               return (_latitude == inOther._latitude) && (_longitude == inOther._longitude);
+       }
+
+       /** @return latitude as int */
+       public int getLatitude() {
+               return _latitude;
+       }
+
+       /** @return longitude as int */
+       public int getLongitude() {
+               return _longitude;
+       }
+
+       /**
+        * @return filename of tile
+        */
+       public String getTileName()
+       {
+               return (_latitude >= 0?"N":"S")
+                       + (Math.abs(_latitude) < 10?"0":"")
+                       + Math.abs(_latitude)
+                       + (_longitude >= 0?"E":"W")
+                       + (Math.abs(_longitude) < 100?"0":"")
+                       + (Math.abs(_longitude) < 10?"0":"")
+                       + Math.abs(_longitude)
+                       + ".hgt.zip";
+       }
+}
diff --git a/tim/prune/function/srtm/TileFinder.java b/tim/prune/function/srtm/TileFinder.java
new file mode 100644 (file)
index 0000000..209db7f
--- /dev/null
@@ -0,0 +1,74 @@
+package tim.prune.function.srtm;
+
+import java.io.InputStream;
+import java.net.MalformedURLException;
+import java.net.URL;
+import java.util.ArrayList;
+
+
+/**
+ * Class to get the URLs of the SRTM tiles
+ * using the srtmtiles.dat file
+ */
+public abstract class TileFinder
+{
+       /** URL prefix for all tiles */
+       private static final String URL_PREFIX = "http://dds.cr.usgs.gov/srtm/version2_1/SRTM3/";
+       /** Directory names for each continent */
+       private static final String[] CONTINENTS = {"", "Eurasia", "North_America", "Australia",
+               "Islands", "South_America", "Africa"};
+
+
+       /**
+        * Get the Urls for the given list of tiles
+        * @param inTiles list of Tiles to get
+        * @return array of URLs
+        */
+       public static URL[] getUrls(ArrayList<SrtmTile> inTiles)
+       {
+               if (inTiles == null || inTiles.size() < 1) {return null;}
+               URL[] urls = new URL[inTiles.size()];
+               // Read dat file into array
+               byte[] lookup = readDatFile();
+               for (int t=0; t<inTiles.size(); t++)
+               {
+                       SrtmTile tile = inTiles.get(t);
+                       // Get byte from lookup array
+                       int idx = (tile.getLatitude() + 59)*360 + (tile.getLongitude() + 180);
+                       try
+                       {
+                               int dir = lookup[idx];
+                               if (dir > 0) {
+                                       try {
+                                               urls[t] = new URL(URL_PREFIX + CONTINENTS[dir] + "/" + tile.getTileName());
+                                       } catch (MalformedURLException e) {} // ignore error, url stays null
+                               }
+                       } catch (ArrayIndexOutOfBoundsException e) {} // ignore error, url stays null
+               }
+               return urls;
+       }
+
+       /**
+        * Read the dat file and get the contents
+        * @return byte array containing file contents
+        */
+       private static byte[] readDatFile()
+       {
+               try
+               {
+                       // Need absolute path to dat file
+                       InputStream in = TileFinder.class.getResourceAsStream("/tim/prune/function/srtm/srtmtiles.dat");
+                       if (in != null)
+                       {
+                               byte[] buffer = new byte[in.available()];
+                               in.read(buffer);
+                               in.close();
+                               return buffer;
+                       }
+               }
+               catch (java.io.IOException e) {
+                       System.err.println("Exception trying to read srtmtiles.dat : " + e.getMessage());
+               }
+               return null;
+       }
+}
diff --git a/tim/prune/function/srtm/gen/GenerateTileLookup.java b/tim/prune/function/srtm/gen/GenerateTileLookup.java
new file mode 100644 (file)
index 0000000..d797b13
--- /dev/null
@@ -0,0 +1,70 @@
+package tim.prune.function.srtm.gen;
+
+import java.io.BufferedReader;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.FileReader;
+
+/**
+ * Class used to generate a lookup file to find the URLs of SRTM tiles.
+ * The tiles are split into directories for each continent, so we need some way
+ * of going from coordinates to directories.
+ * This class reads the directory listings from the files tiles1.txt, tiles2.txt etc
+ * and combines the result into a binary array
+ */
+public class GenerateTileLookup
+{
+
+       /**
+        * Main method for generating the array
+        * @param args ignored
+        */
+       public static void main(String[] args)
+       {
+               System.out.println("Generate tile lookup");
+               byte[] lookup = new byte[360 * 120]; // +/- 180 degrees longitude, +/- 60 degrees latitude
+               for (int f=1; f<= 6; f++)
+               {
+                       try
+                       {
+                               BufferedReader r = new BufferedReader(new FileReader(new File("tim/prune/function/srtm/gen/tiles" + f + ".txt")));
+                               String line = r.readLine();
+                               System.out.println("Read continent: '" + line + "'");
+                               while ((line = r.readLine()) != null) {
+                                       if (line.length() == 7)
+                                       {
+                                               boolean north = (line.charAt(0) == 'N');
+                                               int lat = Integer.parseInt(line.substring(1, 3));
+                                               if (!north) {lat = -lat;}
+                                               boolean east = (line.charAt(3) == 'E');
+                                               int lon = Integer.parseInt(line.substring(4));
+                                               if (!east) {lon = -lon;}
+                                               // Store in lookup
+                                               int arrindex = (lat+59)*360 + (lon+180);
+                                               lookup[arrindex] = (byte) f;
+                                       }
+                               }
+                       }
+                       catch (Exception e) {
+                               e.printStackTrace();
+                       }
+               }
+               // Now f should be populated
+               StringBuilder b = new StringBuilder();
+               for (int l=-180; l<180; l++) {
+                       int i = 59 * 360 + (l+180);
+                       b.append("" + lookup[i]);
+               }
+               System.out.println("equator: " + b.toString());
+
+               // Write bytes to file
+               try {
+                       FileOutputStream out = new FileOutputStream(new File("srtmtiles.dat"));
+                       out.write(lookup);
+                       out.close();
+               }
+               catch (Exception e) {
+                       e.printStackTrace();
+               }
+       }
+}
diff --git a/tim/prune/function/srtm/gen/tiles1.txt b/tim/prune/function/srtm/gen/tiles1.txt
new file mode 100644 (file)
index 0000000..9b88f20
--- /dev/null
@@ -0,0 +1,5878 @@
+Eurasia
+N00E072
+N00E073
+N00E097
+N00E098
+N00E099
+N00E100
+N00E101
+N00E102
+N00E103
+N00E104
+N00E106
+N00E107
+N00E108
+N00E109
+N00E110
+N00E111
+N00E112
+N00E113
+N00E114
+N00E115
+N00E116
+N00E117
+N00E118
+N00E119
+N00E120
+N00E121
+N00E122
+N00E123
+N00E124
+N00E126
+N00E127
+N00E128
+N00E129
+N00E130
+N00E131
+N00E134
+N00E172
+N00E173
+N00W177
+N01E073
+N01E097
+N01E098
+N01E099
+N01E100
+N01E101
+N01E102
+N01E103
+N01E104
+N01E106
+N01E107
+N01E108
+N01E109
+N01E110
+N01E111
+N01E112
+N01E113
+N01E114
+N01E115
+N01E116
+N01E117
+N01E118
+N01E119
+N01E120
+N01E121
+N01E122
+N01E124
+N01E125
+N01E126
+N01E127
+N01E128
+N01E131
+N01E154
+N01E172
+N01E173
+N01W158
+N02E072
+N02E073
+N02E095
+N02E096
+N02E097
+N02E098
+N02E099
+N02E100
+N02E101
+N02E102
+N02E103
+N02E104
+N02E105
+N02E106
+N02E107
+N02E108
+N02E109
+N02E111
+N02E112
+N02E113
+N02E114
+N02E115
+N02E116
+N02E117
+N02E118
+N02E125
+N02E127
+N02E128
+N02E131
+N02E173
+N02W158
+N03E072
+N03E073
+N03E095
+N03E096
+N03E097
+N03E098
+N03E099
+N03E100
+N03E101
+N03E102
+N03E103
+N03E105
+N03E106
+N03E107
+N03E108
+N03E112
+N03E113
+N03E114
+N03E115
+N03E116
+N03E117
+N03E125
+N03E126
+N03E131
+N03E154
+N03E172
+N03E173
+N03W160
+N04E072
+N04E073
+N04E095
+N04E096
+N04E097
+N04E098
+N04E100
+N04E101
+N04E102
+N04E103
+N04E107
+N04E108
+N04E113
+N04E114
+N04E115
+N04E116
+N04E117
+N04E118
+N04E119
+N04E125
+N04E126
+N04E127
+N04E131
+N04E132
+N04E168
+N04W161
+N05E072
+N05E073
+N05E080
+N05E094
+N05E095
+N05E096
+N05E097
+N05E100
+N05E101
+N05E102
+N05E103
+N05E114
+N05E115
+N05E116
+N05E117
+N05E118
+N05E119
+N05E120
+N05E121
+N05E124
+N05E125
+N05E126
+N05E132
+N05E153
+N05E157
+N05E162
+N05E163
+N05E168
+N05E169
+N05E172
+N05W163
+N06E072
+N06E073
+N06E079
+N06E080
+N06E081
+N06E093
+N06E095
+N06E099
+N06E100
+N06E101
+N06E102
+N06E115
+N06E116
+N06E117
+N06E118
+N06E120
+N06E121
+N06E122
+N06E123
+N06E124
+N06E125
+N06E126
+N06E134
+N06E143
+N06E149
+N06E151
+N06E152
+N06E157
+N06E158
+N06E159
+N06E160
+N06E169
+N06E171
+N06E172
+N06W163
+N07E072
+N07E073
+N07E079
+N07E080
+N07E081
+N07E093
+N07E098
+N07E099
+N07E100
+N07E113
+N07E116
+N07E117
+N07E118
+N07E121
+N07E122
+N07E123
+N07E124
+N07E125
+N07E126
+N07E134
+N07E143
+N07E144
+N07E145
+N07E146
+N07E147
+N07E149
+N07E151
+N07E152
+N07E155
+N07E157
+N07E158
+N07E168
+N07E171
+N08E073
+N08E076
+N08E077
+N08E078
+N08E079
+N08E080
+N08E081
+N08E092
+N08E093
+N08E097
+N08E098
+N08E099
+N08E100
+N08E104
+N08E105
+N08E106
+N08E111
+N08E116
+N08E117
+N08E118
+N08E122
+N08E123
+N08E124
+N08E125
+N08E126
+N08E134
+N08E137
+N08E140
+N08E144
+N08E146
+N08E147
+N08E149
+N08E150
+N08E151
+N08E152
+N08E154
+N08E165
+N08E166
+N08E167
+N08E168
+N08E170
+N08E171
+N09E076
+N09E077
+N09E078
+N09E079
+N09E080
+N09E092
+N09E097
+N09E098
+N09E099
+N09E100
+N09E102
+N09E103
+N09E104
+N09E105
+N09E106
+N09E109
+N09E117
+N09E118
+N09E119
+N09E120
+N09E121
+N09E122
+N09E123
+N09E124
+N09E125
+N09E126
+N09E138
+N09E139
+N09E140
+N09E145
+N09E160
+N09E165
+N09E166
+N09E167
+N09E169
+N09E170
+N10E072
+N10E073
+N10E075
+N10E076
+N10E077
+N10E078
+N10E079
+N10E092
+N10E097
+N10E098
+N10E099
+N10E102
+N10E103
+N10E104
+N10E105
+N10E106
+N10E107
+N10E108
+N10E114
+N10E115
+N10E118
+N10E119
+N10E120
+N10E121
+N10E122
+N10E123
+N10E124
+N10E125
+N10E126
+N10E139
+N10E165
+N10E166
+N10E168
+N10E169
+N10E170
+N11E072
+N11E073
+N11E075
+N11E076
+N11E077
+N11E078
+N11E079
+N11E092
+N11E093
+N11E097
+N11E098
+N11E099
+N11E102
+N11E103
+N11E104
+N11E105
+N11E106
+N11E107
+N11E108
+N11E109
+N11E114
+N11E115
+N11E119
+N11E120
+N11E121
+N11E122
+N11E123
+N11E124
+N11E125
+N11E162
+N11E165
+N11E166
+N11E167
+N11E169
+N12E074
+N12E075
+N12E076
+N12E077
+N12E078
+N12E079
+N12E080
+N12E092
+N12E093
+N12E097
+N12E098
+N12E099
+N12E100
+N12E101
+N12E102
+N12E103
+N12E104
+N12E105
+N12E106
+N12E107
+N12E108
+N12E109
+N12E119
+N12E120
+N12E121
+N12E122
+N12E123
+N12E124
+N12E125
+N12E170
+N13E074
+N13E075
+N13E076
+N13E077
+N13E078
+N13E079
+N13E080
+N13E092
+N13E093
+N13E094
+N13E097
+N13E098
+N13E099
+N13E100
+N13E101
+N13E102
+N13E103
+N13E104
+N13E105
+N13E106
+N13E107
+N13E108
+N13E109
+N13E120
+N13E121
+N13E122
+N13E123
+N13E124
+N13E144
+N14E074
+N14E075
+N14E076
+N14E077
+N14E078
+N14E079
+N14E080
+N14E093
+N14E097
+N14E098
+N14E099
+N14E100
+N14E101
+N14E102
+N14E103
+N14E104
+N14E105
+N14E106
+N14E107
+N14E108
+N14E109
+N14E120
+N14E121
+N14E122
+N14E123
+N14E124
+N14E145
+N14E168
+N14E169
+N15E073
+N15E074
+N15E075
+N15E076
+N15E077
+N15E078
+N15E079
+N15E080
+N15E081
+N15E094
+N15E095
+N15E097
+N15E098
+N15E099
+N15E100
+N15E101
+N15E102
+N15E103
+N15E104
+N15E105
+N15E106
+N15E107
+N15E108
+N15E109
+N15E111
+N15E119
+N15E120
+N15E121
+N15E122
+N15E145
+N16E073
+N16E074
+N16E075
+N16E076
+N16E077
+N16E078
+N16E079
+N16E080
+N16E081
+N16E082
+N16E094
+N16E095
+N16E096
+N16E097
+N16E098
+N16E099
+N16E100
+N16E101
+N16E102
+N16E103
+N16E104
+N16E105
+N16E106
+N16E107
+N16E108
+N16E111
+N16E112
+N16E119
+N16E120
+N16E121
+N16E122
+N16E145
+N16E146
+N17E073
+N17E074
+N17E075
+N17E076
+N17E077
+N17E078
+N17E079
+N17E080
+N17E081
+N17E082
+N17E083
+N17E094
+N17E095
+N17E096
+N17E097
+N17E098
+N17E099
+N17E100
+N17E101
+N17E102
+N17E103
+N17E104
+N17E105
+N17E106
+N17E107
+N17E120
+N17E121
+N17E122
+N17E145
+N18E072
+N18E073
+N18E074
+N18E075
+N18E076
+N18E077
+N18E078
+N18E079
+N18E080
+N18E081
+N18E082
+N18E083
+N18E084
+N18E093
+N18E094
+N18E095
+N18E096
+N18E097
+N18E098
+N18E099
+N18E100
+N18E101
+N18E102
+N18E103
+N18E104
+N18E105
+N18E106
+N18E108
+N18E109
+N18E110
+N18E120
+N18E121
+N18E122
+N18E145
+N19E072
+N19E073
+N19E074
+N19E075
+N19E076
+N19E077
+N19E078
+N19E079
+N19E080
+N19E081
+N19E082
+N19E083
+N19E084
+N19E085
+N19E086
+N19E092
+N19E093
+N19E094
+N19E095
+N19E096
+N19E097
+N19E098
+N19E099
+N19E100
+N19E101
+N19E102
+N19E103
+N19E104
+N19E105
+N19E106
+N19E108
+N19E109
+N19E110
+N19E111
+N19E121
+N19E122
+N19E145
+N19E166
+N20E070
+N20E071
+N20E072
+N20E073
+N20E074
+N20E075
+N20E076
+N20E077
+N20E078
+N20E079
+N20E080
+N20E081
+N20E082
+N20E083
+N20E084
+N20E085
+N20E086
+N20E087
+N20E092
+N20E093
+N20E094
+N20E095
+N20E096
+N20E097
+N20E098
+N20E099
+N20E100
+N20E101
+N20E102
+N20E103
+N20E104
+N20E105
+N20E106
+N20E107
+N20E109
+N20E110
+N20E116
+N20E121
+N20E122
+N20E136
+N20E144
+N20E145
+N21E069
+N21E070
+N21E071
+N21E072
+N21E073
+N21E074
+N21E075
+N21E076
+N21E077
+N21E078
+N21E079
+N21E080
+N21E081
+N21E082
+N21E083
+N21E084
+N21E085
+N21E086
+N21E087
+N21E088
+N21E089
+N21E090
+N21E091
+N21E092
+N21E093
+N21E094
+N21E095
+N21E096
+N21E097
+N21E098
+N21E099
+N21E100
+N21E101
+N21E102
+N21E103
+N21E104
+N21E105
+N21E106
+N21E107
+N21E108
+N21E109
+N21E110
+N21E111
+N21E112
+N21E113
+N21E114
+N21E120
+N21E121
+N22E068
+N22E069
+N22E070
+N22E071
+N22E072
+N22E073
+N22E074
+N22E075
+N22E076
+N22E077
+N22E078
+N22E079
+N22E080
+N22E081
+N22E082
+N22E083
+N22E084
+N22E085
+N22E086
+N22E087
+N22E088
+N22E089
+N22E090
+N22E091
+N22E092
+N22E093
+N22E094
+N22E095
+N22E096
+N22E097
+N22E098
+N22E099
+N22E100
+N22E101
+N22E102
+N22E103
+N22E104
+N22E105
+N22E106
+N22E107
+N22E108
+N22E109
+N22E110
+N22E111
+N22E112
+N22E113
+N22E114
+N22E115
+N22E116
+N22E120
+N22E121
+N23E067
+N23E068
+N23E069
+N23E070
+N23E071
+N23E072
+N23E073
+N23E074
+N23E075
+N23E076
+N23E077
+N23E078
+N23E079
+N23E080
+N23E081
+N23E082
+N23E083
+N23E084
+N23E085
+N23E086
+N23E087
+N23E088
+N23E089
+N23E090
+N23E091
+N23E092
+N23E093
+N23E094
+N23E095
+N23E096
+N23E097
+N23E098
+N23E099
+N23E100
+N23E101
+N23E102
+N23E103
+N23E104
+N23E105
+N23E106
+N23E107
+N23E108
+N23E109
+N23E110
+N23E111
+N23E112
+N23E113
+N23E114
+N23E115
+N23E116
+N23E117
+N23E119
+N23E120
+N23E121
+N24E066
+N24E067
+N24E068
+N24E069
+N24E070
+N24E071
+N24E072
+N24E073
+N24E074
+N24E075
+N24E076
+N24E077
+N24E078
+N24E079
+N24E080
+N24E081
+N24E082
+N24E083
+N24E084
+N24E085
+N24E086
+N24E087
+N24E088
+N24E089
+N24E090
+N24E091
+N24E092
+N24E093
+N24E094
+N24E095
+N24E096
+N24E097
+N24E098
+N24E099
+N24E100
+N24E101
+N24E102
+N24E103
+N24E104
+N24E105
+N24E106
+N24E107
+N24E108
+N24E109
+N24E110
+N24E111
+N24E112
+N24E113
+N24E114
+N24E115
+N24E116
+N24E117
+N24E118
+N24E119
+N24E120
+N24E121
+N24E122
+N24E123
+N24E124
+N24E125
+N24E131
+N24E141
+N24E153
+N25E060
+N25E061
+N25E062
+N25E063
+N25E064
+N25E065
+N25E066
+N25E067
+N25E068
+N25E069
+N25E070
+N25E071
+N25E072
+N25E073
+N25E074
+N25E075
+N25E076
+N25E077
+N25E078
+N25E079
+N25E080
+N25E081
+N25E082
+N25E083
+N25E084
+N25E085
+N25E086
+N25E087
+N25E088
+N25E089
+N25E090
+N25E091
+N25E092
+N25E093
+N25E094
+N25E095
+N25E096
+N25E097
+N25E098
+N25E099
+N25E100
+N25E101
+N25E102
+N25E103
+N25E104
+N25E105
+N25E106
+N25E107
+N25E108
+N25E109
+N25E110
+N25E111
+N25E112
+N25E113
+N25E114
+N25E115
+N25E116
+N25E117
+N25E118
+N25E119
+N25E121
+N25E122
+N25E123
+N25E124
+N25E131
+N25E141
+N26E060
+N26E061
+N26E062
+N26E063
+N26E064
+N26E065
+N26E066
+N26E067
+N26E068
+N26E069
+N26E070
+N26E071
+N26E072
+N26E073
+N26E074
+N26E075
+N26E076
+N26E077
+N26E078
+N26E079
+N26E080
+N26E081
+N26E082
+N26E083
+N26E084
+N26E085
+N26E086
+N26E087
+N26E088
+N26E089
+N26E090
+N26E091
+N26E092
+N26E093
+N26E094
+N26E095
+N26E096
+N26E097
+N26E098
+N26E099
+N26E100
+N26E101
+N26E102
+N26E103
+N26E104
+N26E105
+N26E106
+N26E107
+N26E108
+N26E109
+N26E110
+N26E111
+N26E112
+N26E113
+N26E114
+N26E115
+N26E116
+N26E117
+N26E118
+N26E119
+N26E120
+N26E126
+N26E127
+N26E128
+N26E142
+N27E060
+N27E061
+N27E062
+N27E063
+N27E064
+N27E065
+N27E066
+N27E067
+N27E068
+N27E069
+N27E070
+N27E071
+N27E072
+N27E073
+N27E074
+N27E075
+N27E076
+N27E077
+N27E078
+N27E079
+N27E080
+N27E081
+N27E082
+N27E083
+N27E084
+N27E085
+N27E086
+N27E087
+N27E088
+N27E089
+N27E090
+N27E091
+N27E092
+N27E093
+N27E094
+N27E095
+N27E096
+N27E097
+N27E098
+N27E099
+N27E100
+N27E101
+N27E102
+N27E103
+N27E104
+N27E105
+N27E106
+N27E107
+N27E108
+N27E109
+N27E110
+N27E111
+N27E112
+N27E113
+N27E114
+N27E115
+N27E116
+N27E117
+N27E118
+N27E119
+N27E120
+N27E121
+N27E127
+N27E128
+N27E129
+N27E140
+N27E142
+N28E060
+N28E061
+N28E062
+N28E063
+N28E064
+N28E065
+N28E066
+N28E067
+N28E068
+N28E069
+N28E070
+N28E071
+N28E072
+N28E073
+N28E074
+N28E075
+N28E076
+N28E077
+N28E078
+N28E079
+N28E080
+N28E081
+N28E082
+N28E083
+N28E084
+N28E085
+N28E086
+N28E087
+N28E088
+N28E089
+N28E090
+N28E091
+N28E092
+N28E093
+N28E094
+N28E095
+N28E096
+N28E097
+N28E098
+N28E099
+N28E100
+N28E101
+N28E102
+N28E103
+N28E104
+N28E105
+N28E106
+N28E107
+N28E108
+N28E109
+N28E110
+N28E111
+N28E112
+N28E113
+N28E114
+N28E115
+N28E116
+N28E117
+N28E118
+N28E119
+N28E120
+N28E121
+N28E122
+N28E128
+N28E129
+N28E130
+N29E060
+N29E061
+N29E062
+N29E063
+N29E064
+N29E065
+N29E066
+N29E067
+N29E068
+N29E069
+N29E070
+N29E071
+N29E072
+N29E073
+N29E074
+N29E075
+N29E076
+N29E077
+N29E078
+N29E079
+N29E080
+N29E081
+N29E082
+N29E083
+N29E084
+N29E085
+N29E086
+N29E087
+N29E088
+N29E089
+N29E090
+N29E091
+N29E092
+N29E093
+N29E094
+N29E095
+N29E096
+N29E097
+N29E098
+N29E099
+N29E100
+N29E101
+N29E102
+N29E103
+N29E104
+N29E105
+N29E106
+N29E107
+N29E108
+N29E109
+N29E110
+N29E111
+N29E112
+N29E113
+N29E114
+N29E115
+N29E116
+N29E117
+N29E118
+N29E119
+N29E120
+N29E121
+N29E122
+N29E129
+N29E140
+N30E060
+N30E061
+N30E062
+N30E063
+N30E064
+N30E065
+N30E066
+N30E067
+N30E068
+N30E069
+N30E070
+N30E071
+N30E072
+N30E073
+N30E074
+N30E075
+N30E076
+N30E077
+N30E078
+N30E079
+N30E080
+N30E081
+N30E082
+N30E083
+N30E084
+N30E085
+N30E086
+N30E087
+N30E088
+N30E089
+N30E090
+N30E091
+N30E092
+N30E093
+N30E094
+N30E095
+N30E096
+N30E097
+N30E098
+N30E099
+N30E100
+N30E101
+N30E102
+N30E103
+N30E104
+N30E105
+N30E106
+N30E107
+N30E108
+N30E109
+N30E110
+N30E111
+N30E112
+N30E113
+N30E114
+N30E115
+N30E116
+N30E117
+N30E118
+N30E119
+N30E120
+N30E121
+N30E122
+N30E129
+N30E130
+N30E131
+N30E140
+N31E060
+N31E061
+N31E062
+N31E063
+N31E064
+N31E065
+N31E066
+N31E067
+N31E068
+N31E069
+N31E070
+N31E071
+N31E072
+N31E073
+N31E074
+N31E075
+N31E076
+N31E077
+N31E078
+N31E079
+N31E080
+N31E081
+N31E082
+N31E083
+N31E084
+N31E085
+N31E086
+N31E087
+N31E088
+N31E089
+N31E090
+N31E091
+N31E092
+N31E093
+N31E094
+N31E095
+N31E096
+N31E097
+N31E098
+N31E099
+N31E100
+N31E101
+N31E102
+N31E103
+N31E104
+N31E105
+N31E106
+N31E107
+N31E108
+N31E109
+N31E110
+N31E111
+N31E112
+N31E113
+N31E114
+N31E115
+N31E116
+N31E117
+N31E118
+N31E119
+N31E120
+N31E121
+N31E122
+N31E128
+N31E129
+N31E130
+N31E131
+N31E139
+N31E140
+N32E060
+N32E061
+N32E062
+N32E063
+N32E064
+N32E065
+N32E066
+N32E067
+N32E068
+N32E069
+N32E070
+N32E071
+N32E072
+N32E073
+N32E074
+N32E075
+N32E076
+N32E077
+N32E078
+N32E079
+N32E080
+N32E081
+N32E082
+N32E083
+N32E084
+N32E085
+N32E086
+N32E087
+N32E088
+N32E089
+N32E090
+N32E091
+N32E092
+N32E093
+N32E094
+N32E095
+N32E096
+N32E097
+N32E098
+N32E099
+N32E100
+N32E101
+N32E102
+N32E103
+N32E104
+N32E105
+N32E106
+N32E107
+N32E108
+N32E109
+N32E110
+N32E111
+N32E112
+N32E113
+N32E114
+N32E115
+N32E116
+N32E117
+N32E118
+N32E119
+N32E120
+N32E121
+N32E128
+N32E129
+N32E130
+N32E131
+N32E132
+N32E133
+N32E139
+N33E060
+N33E061
+N33E062
+N33E063
+N33E064
+N33E065
+N33E066
+N33E067
+N33E068
+N33E069
+N33E070
+N33E071
+N33E072
+N33E073
+N33E074
+N33E075
+N33E076
+N33E077
+N33E078
+N33E079
+N33E080
+N33E081
+N33E082
+N33E083
+N33E084
+N33E085
+N33E086
+N33E087
+N33E088
+N33E089
+N33E090
+N33E091
+N33E092
+N33E093
+N33E094
+N33E095
+N33E096
+N33E097
+N33E098
+N33E099
+N33E100
+N33E101
+N33E102
+N33E103
+N33E104
+N33E105
+N33E106
+N33E107
+N33E108
+N33E109
+N33E110
+N33E111
+N33E112
+N33E113
+N33E114
+N33E115
+N33E116
+N33E117
+N33E118
+N33E119
+N33E120
+N33E126
+N33E128
+N33E129
+N33E130
+N33E131
+N33E132
+N33E133
+N33E134
+N33E135
+N33E136
+N33E138
+N33E139
+N34E060
+N34E061
+N34E062
+N34E063
+N34E064
+N34E065
+N34E066
+N34E067
+N34E068
+N34E069
+N34E070
+N34E071
+N34E072
+N34E073
+N34E074
+N34E075
+N34E076
+N34E077
+N34E078
+N34E079
+N34E080
+N34E081
+N34E082
+N34E083
+N34E084
+N34E085
+N34E086
+N34E087
+N34E088
+N34E089
+N34E090
+N34E091
+N34E092
+N34E093
+N34E094
+N34E095
+N34E096
+N34E097
+N34E098
+N34E099
+N34E100
+N34E101
+N34E102
+N34E103
+N34E104
+N34E105
+N34E106
+N34E107
+N34E108
+N34E109
+N34E110
+N34E111
+N34E112
+N34E113
+N34E114
+N34E115
+N34E116
+N34E117
+N34E118
+N34E119
+N34E120
+N34E125
+N34E126
+N34E127
+N34E128
+N34E129
+N34E130
+N34E131
+N34E132
+N34E133
+N34E134
+N34E135
+N34E136
+N34E137
+N34E138
+N34E139
+N35E000
+N35E001
+N35E002
+N35E003
+N35E004
+N35E005
+N35E006
+N35E007
+N35E008
+N35E009
+N35E010
+N35E011
+N35E012
+N35E014
+N35E023
+N35E024
+N35E025
+N35E026
+N35E027
+N35E032
+N35E033
+N35E034
+N35E035
+N35E036
+N35E037
+N35E038
+N35E039
+N35E040
+N35E041
+N35E042
+N35E043
+N35E044
+N35E045
+N35E046
+N35E047
+N35E048
+N35E049
+N35E050
+N35E051
+N35E052
+N35E053
+N35E054
+N35E055
+N35E056
+N35E057
+N35E058
+N35E059
+N35E060
+N35E061
+N35E062
+N35E063
+N35E064
+N35E065
+N35E066
+N35E067
+N35E068
+N35E069
+N35E070
+N35E071
+N35E072
+N35E073
+N35E074
+N35E075
+N35E076
+N35E077
+N35E078
+N35E079
+N35E080
+N35E081
+N35E082
+N35E083
+N35E084
+N35E085
+N35E086
+N35E087
+N35E088
+N35E089
+N35E090
+N35E091
+N35E092
+N35E093
+N35E094
+N35E095
+N35E096
+N35E097
+N35E098
+N35E099
+N35E100
+N35E101
+N35E102
+N35E103
+N35E104
+N35E105
+N35E106
+N35E107
+N35E108
+N35E109
+N35E110
+N35E111
+N35E112
+N35E113
+N35E114
+N35E115
+N35E116
+N35E117
+N35E118
+N35E119
+N35E120
+N35E125
+N35E126
+N35E127
+N35E128
+N35E129
+N35E132
+N35E133
+N35E134
+N35E135
+N35E136
+N35E137
+N35E138
+N35E139
+N35E140
+N35W001
+N35W002
+N35W003
+N35W004
+N35W005
+N35W006
+N35W007
+N36E000
+N36E001
+N36E002
+N36E003
+N36E004
+N36E005
+N36E006
+N36E007
+N36E008
+N36E009
+N36E010
+N36E011
+N36E012
+N36E014
+N36E015
+N36E021
+N36E022
+N36E023
+N36E024
+N36E025
+N36E026
+N36E027
+N36E028
+N36E029
+N36E030
+N36E031
+N36E032
+N36E033
+N36E034
+N36E035
+N36E036
+N36E037
+N36E038
+N36E039
+N36E040
+N36E041
+N36E042
+N36E043
+N36E044
+N36E045
+N36E046
+N36E047
+N36E048
+N36E049
+N36E050
+N36E051
+N36E052
+N36E053
+N36E054
+N36E055
+N36E056
+N36E057
+N36E058
+N36E059
+N36E060
+N36E061
+N36E062
+N36E063
+N36E064
+N36E065
+N36E066
+N36E067
+N36E068
+N36E069
+N36E070
+N36E071
+N36E072
+N36E073
+N36E074
+N36E075
+N36E076
+N36E077
+N36E078
+N36E079
+N36E080
+N36E081
+N36E082
+N36E083
+N36E084
+N36E085
+N36E086
+N36E087
+N36E088
+N36E089
+N36E090
+N36E091
+N36E092
+N36E093
+N36E094
+N36E095
+N36E096
+N36E097
+N36E098
+N36E099
+N36E100
+N36E101
+N36E102
+N36E103
+N36E104
+N36E105
+N36E106
+N36E107
+N36E108
+N36E109
+N36E110
+N36E111
+N36E112
+N36E113
+N36E114
+N36E115
+N36E116
+N36E117
+N36E118
+N36E119
+N36E120
+N36E121
+N36E122
+N36E125
+N36E126
+N36E127
+N36E128
+N36E129
+N36E132
+N36E133
+N36E135
+N36E136
+N36E137
+N36E138
+N36E139
+N36E140
+N36W002
+N36W003
+N36W004
+N36W005
+N36W006
+N36W007
+N36W008
+N36W009
+N37E006
+N37E007
+N37E008
+N37E009
+N37E010
+N37E011
+N37E012
+N37E013
+N37E014
+N37E015
+N37E016
+N37E020
+N37E021
+N37E022
+N37E023
+N37E024
+N37E025
+N37E026
+N37E027
+N37E028
+N37E029
+N37E030
+N37E031
+N37E032
+N37E033
+N37E034
+N37E035
+N37E036
+N37E037
+N37E038
+N37E039
+N37E040
+N37E041
+N37E042
+N37E043
+N37E044
+N37E045
+N37E046
+N37E047
+N37E048
+N37E049
+N37E050
+N37E053
+N37E054
+N37E055
+N37E056
+N37E057
+N37E058
+N37E059
+N37E060
+N37E061
+N37E062
+N37E063
+N37E064
+N37E065
+N37E066
+N37E067
+N37E068
+N37E069
+N37E070
+N37E071
+N37E072
+N37E073
+N37E074
+N37E075
+N37E076
+N37E077
+N37E078
+N37E079
+N37E080
+N37E081
+N37E082
+N37E083
+N37E084
+N37E085
+N37E086
+N37E087
+N37E088
+N37E089
+N37E090
+N37E091
+N37E092
+N37E093
+N37E094
+N37E095
+N37E096
+N37E097
+N37E098
+N37E099
+N37E100
+N37E101
+N37E102
+N37E103
+N37E104
+N37E105
+N37E106
+N37E107
+N37E108
+N37E109
+N37E110
+N37E111
+N37E112
+N37E113
+N37E114
+N37E115
+N37E116
+N37E117
+N37E118
+N37E119
+N37E120
+N37E121
+N37E122
+N37E124
+N37E125
+N37E126
+N37E127
+N37E128
+N37E129
+N37E130
+N37E131
+N37E136
+N37E137
+N37E138
+N37E139
+N37E140
+N37E141
+N37W001
+N37W002
+N37W003
+N37W004
+N37W005
+N37W006
+N37W007
+N37W008
+N37W009
+N38E000
+N38E001
+N38E008
+N38E009
+N38E012
+N38E013
+N38E014
+N38E015
+N38E016
+N38E017
+N38E020
+N38E021
+N38E022
+N38E023
+N38E024
+N38E025
+N38E026
+N38E027
+N38E028
+N38E029
+N38E030
+N38E031
+N38E032
+N38E033
+N38E034
+N38E035
+N38E036
+N38E037
+N38E038
+N38E039
+N38E040
+N38E041
+N38E042
+N38E043
+N38E044
+N38E045
+N38E046
+N38E047
+N38E048
+N38E049
+N38E053
+N38E054
+N38E055
+N38E056
+N38E057
+N38E058
+N38E059
+N38E060
+N38E061
+N38E062
+N38E063
+N38E064
+N38E065
+N38E066
+N38E067
+N38E068
+N38E069
+N38E070
+N38E071
+N38E072
+N38E073
+N38E074
+N38E075
+N38E076
+N38E077
+N38E078
+N38E079
+N38E080
+N38E081
+N38E082
+N38E083
+N38E084
+N38E085
+N38E086
+N38E087
+N38E088
+N38E089
+N38E090
+N38E091
+N38E092
+N38E093
+N38E094
+N38E095
+N38E096
+N38E097
+N38E098
+N38E099
+N38E100
+N38E101
+N38E102
+N38E103
+N38E104
+N38E105
+N38E106
+N38E107
+N38E108
+N38E109
+N38E110
+N38E111
+N38E112
+N38E113
+N38E114
+N38E115
+N38E116
+N38E117
+N38E118
+N38E120
+N38E121
+N38E124
+N38E125
+N38E126
+N38E127
+N38E128
+N38E138
+N38E139
+N38E140
+N38E141
+N38W001
+N38W002
+N38W003
+N38W004
+N38W005
+N38W006
+N38W007
+N38W008
+N38W009
+N38W010
+N39E000
+N39E001
+N39E002
+N39E003
+N39E004
+N39E008
+N39E009
+N39E015
+N39E016
+N39E017
+N39E018
+N39E019
+N39E020
+N39E021
+N39E022
+N39E023
+N39E024
+N39E025
+N39E026
+N39E027
+N39E028
+N39E029
+N39E030
+N39E031
+N39E032
+N39E033
+N39E034
+N39E035
+N39E036
+N39E037
+N39E038
+N39E039
+N39E040
+N39E041
+N39E042
+N39E043
+N39E044
+N39E045
+N39E046
+N39E047
+N39E048
+N39E049
+N39E052
+N39E053
+N39E054
+N39E055
+N39E056
+N39E057
+N39E058
+N39E059
+N39E060
+N39E061
+N39E062
+N39E063
+N39E064
+N39E065
+N39E066
+N39E067
+N39E068
+N39E069
+N39E070
+N39E071
+N39E072
+N39E073
+N39E074
+N39E075
+N39E076
+N39E077
+N39E078
+N39E079
+N39E080
+N39E081
+N39E082
+N39E083
+N39E084
+N39E085
+N39E086
+N39E087
+N39E088
+N39E089
+N39E090
+N39E091
+N39E092
+N39E093
+N39E094
+N39E095
+N39E096
+N39E097
+N39E098
+N39E099
+N39E100
+N39E101
+N39E102
+N39E103
+N39E104
+N39E105
+N39E106
+N39E107
+N39E108
+N39E109
+N39E110
+N39E111
+N39E112
+N39E113
+N39E114
+N39E115
+N39E116
+N39E117
+N39E118
+N39E119
+N39E121
+N39E122
+N39E123
+N39E124
+N39E125
+N39E126
+N39E127
+N39E128
+N39E139
+N39E140
+N39E141
+N39E142
+N39W001
+N39W002
+N39W003
+N39W004
+N39W005
+N39W006
+N39W007
+N39W008
+N39W009
+N39W010
+N40E000
+N40E003
+N40E004
+N40E008
+N40E009
+N40E012
+N40E013
+N40E014
+N40E015
+N40E016
+N40E017
+N40E018
+N40E019
+N40E020
+N40E021
+N40E022
+N40E023
+N40E024
+N40E025
+N40E026
+N40E027
+N40E028
+N40E029
+N40E030
+N40E031
+N40E032
+N40E033
+N40E034
+N40E035
+N40E036
+N40E037
+N40E038
+N40E039
+N40E040
+N40E041
+N40E042
+N40E043
+N40E044
+N40E045
+N40E046
+N40E047
+N40E048
+N40E049
+N40E050
+N40E052
+N40E053
+N40E054
+N40E055
+N40E056
+N40E057
+N40E058
+N40E059
+N40E060
+N40E061
+N40E062
+N40E063
+N40E064
+N40E065
+N40E066
+N40E067
+N40E068
+N40E069
+N40E070
+N40E071
+N40E072
+N40E073
+N40E074
+N40E075
+N40E076
+N40E077
+N40E078
+N40E079
+N40E080
+N40E081
+N40E082
+N40E083
+N40E084
+N40E085
+N40E086
+N40E087
+N40E088
+N40E089
+N40E090
+N40E091
+N40E092
+N40E093
+N40E094
+N40E095
+N40E096
+N40E097
+N40E098
+N40E099
+N40E100
+N40E101
+N40E102
+N40E103
+N40E104
+N40E105
+N40E106
+N40E107
+N40E108
+N40E109
+N40E110
+N40E111
+N40E112
+N40E113
+N40E114
+N40E115
+N40E116
+N40E117
+N40E118
+N40E119
+N40E120
+N40E121
+N40E122
+N40E123
+N40E124
+N40E125
+N40E126
+N40E127
+N40E128
+N40E129
+N40E139
+N40E140
+N40E141
+N40W001
+N40W002
+N40W003
+N40W004
+N40W005
+N40W006
+N40W007
+N40W008
+N40W009
+N41E000
+N41E001
+N41E002
+N41E003
+N41E008
+N41E009
+N41E011
+N41E012
+N41E013
+N41E014
+N41E015
+N41E016
+N41E017
+N41E019
+N41E020
+N41E021
+N41E022
+N41E023
+N41E024
+N41E025
+N41E026
+N41E027
+N41E028
+N41E029
+N41E030
+N41E031
+N41E032
+N41E033
+N41E034
+N41E035
+N41E036
+N41E037
+N41E038
+N41E039
+N41E040
+N41E041
+N41E042
+N41E043
+N41E044
+N41E045
+N41E046
+N41E047
+N41E048
+N41E049
+N41E052
+N41E053
+N41E054
+N41E055
+N41E056
+N41E057
+N41E058
+N41E059
+N41E060
+N41E061
+N41E062
+N41E063
+N41E064
+N41E065
+N41E066
+N41E067
+N41E068
+N41E069
+N41E070
+N41E071
+N41E072
+N41E073
+N41E074
+N41E075
+N41E076
+N41E077
+N41E078
+N41E079
+N41E080
+N41E081
+N41E082
+N41E083
+N41E084
+N41E085
+N41E086
+N41E087
+N41E088
+N41E089
+N41E090
+N41E091
+N41E092
+N41E093
+N41E094
+N41E095
+N41E096
+N41E097
+N41E098
+N41E099
+N41E100
+N41E101
+N41E102
+N41E103
+N41E104
+N41E105
+N41E106
+N41E107
+N41E108
+N41E109
+N41E110
+N41E111
+N41E112
+N41E113
+N41E114
+N41E115
+N41E116
+N41E117
+N41E118
+N41E119
+N41E120
+N41E121
+N41E122
+N41E123
+N41E124
+N41E125
+N41E126
+N41E127
+N41E128
+N41E129
+N41E130
+N41E139
+N41E140
+N41E141
+N41E143
+N41W001
+N41W002
+N41W003
+N41W004
+N41W005
+N41W006
+N41W007
+N41W008
+N41W009
+N42E000
+N42E001
+N42E002
+N42E003
+N42E006
+N42E008
+N42E009
+N42E010
+N42E011
+N42E012
+N42E013
+N42E014
+N42E015
+N42E016
+N42E017
+N42E018
+N42E019
+N42E020
+N42E021
+N42E022
+N42E023
+N42E024
+N42E025
+N42E026
+N42E027
+N42E028
+N42E033
+N42E034
+N42E035
+N42E040
+N42E041
+N42E042
+N42E043
+N42E044
+N42E045
+N42E046
+N42E047
+N42E048
+N42E051
+N42E052
+N42E053
+N42E054
+N42E055
+N42E056
+N42E057
+N42E058
+N42E059
+N42E060
+N42E061
+N42E062
+N42E063
+N42E064
+N42E065
+N42E066
+N42E067
+N42E068
+N42E069
+N42E070
+N42E071
+N42E072
+N42E073
+N42E074
+N42E075
+N42E076
+N42E077
+N42E078
+N42E079
+N42E080
+N42E081
+N42E082
+N42E083
+N42E084
+N42E085
+N42E086
+N42E087
+N42E088
+N42E089
+N42E090
+N42E091
+N42E092
+N42E093
+N42E094
+N42E095
+N42E096
+N42E097
+N42E098
+N42E099
+N42E100
+N42E101
+N42E102
+N42E103
+N42E104
+N42E105
+N42E106
+N42E107
+N42E108
+N42E109
+N42E110
+N42E111
+N42E112
+N42E113
+N42E114
+N42E115
+N42E116
+N42E117
+N42E118
+N42E119
+N42E120
+N42E121
+N42E122
+N42E123
+N42E124
+N42E125
+N42E126
+N42E127
+N42E128
+N42E129
+N42E130
+N42E131
+N42E132
+N42E133
+N42E134
+N42E139
+N42E140
+N42E141
+N42E142
+N42E143
+N42E144
+N42E145
+N42W001
+N42W002
+N42W003
+N42W004
+N42W005
+N42W006
+N42W007
+N42W008
+N42W009
+N42W010
+N43E000
+N43E001
+N43E002
+N43E003
+N43E004
+N43E005
+N43E006
+N43E007
+N43E008
+N43E009
+N43E010
+N43E011
+N43E012
+N43E013
+N43E015
+N43E016
+N43E017
+N43E018
+N43E019
+N43E020
+N43E021
+N43E022
+N43E023
+N43E024
+N43E025
+N43E026
+N43E027
+N43E028
+N43E039
+N43E040
+N43E041
+N43E042
+N43E043
+N43E044
+N43E045
+N43E046
+N43E047
+N43E050
+N43E051
+N43E052
+N43E053
+N43E054
+N43E055
+N43E056
+N43E057
+N43E058
+N43E059
+N43E060
+N43E061
+N43E062
+N43E063
+N43E064
+N43E065
+N43E066
+N43E067
+N43E068
+N43E069
+N43E070
+N43E071
+N43E072
+N43E073
+N43E074
+N43E075
+N43E076
+N43E077
+N43E078
+N43E079
+N43E080
+N43E081
+N43E082
+N43E083
+N43E084
+N43E085
+N43E086
+N43E087
+N43E088
+N43E089
+N43E090
+N43E091
+N43E092
+N43E093
+N43E094
+N43E095
+N43E096
+N43E097
+N43E098
+N43E099
+N43E100
+N43E101
+N43E102
+N43E103
+N43E104
+N43E105
+N43E106
+N43E107
+N43E108
+N43E109
+N43E110
+N43E111
+N43E112
+N43E113
+N43E114
+N43E115
+N43E116
+N43E117
+N43E118
+N43E119
+N43E120
+N43E121
+N43E122
+N43E123
+N43E124
+N43E125
+N43E126
+N43E127
+N43E128
+N43E129
+N43E130
+N43E131
+N43E132
+N43E133
+N43E134
+N43E135
+N43E140
+N43E141
+N43E142
+N43E143
+N43E144
+N43E145
+N43E146
+N43W001
+N43W002
+N43W003
+N43W004
+N43W005
+N43W006
+N43W007
+N43W008
+N43W009
+N43W010
+N44E000
+N44E001
+N44E002
+N44E003
+N44E004
+N44E005
+N44E006
+N44E007
+N44E008
+N44E009
+N44E010
+N44E011
+N44E012
+N44E013
+N44E014
+N44E015
+N44E016
+N44E017
+N44E018
+N44E019
+N44E020
+N44E021
+N44E022
+N44E023
+N44E024
+N44E025
+N44E026
+N44E027
+N44E028
+N44E029
+N44E033
+N44E034
+N44E035
+N44E037
+N44E038
+N44E039
+N44E040
+N44E041
+N44E042
+N44E043
+N44E044
+N44E045
+N44E046
+N44E047
+N44E050
+N44E051
+N44E052
+N44E053
+N44E054
+N44E055
+N44E056
+N44E057
+N44E058
+N44E059
+N44E060
+N44E061
+N44E062
+N44E063
+N44E064
+N44E065
+N44E066
+N44E067
+N44E068
+N44E069
+N44E070
+N44E071
+N44E072
+N44E073
+N44E074
+N44E075
+N44E076
+N44E077
+N44E078
+N44E079
+N44E080
+N44E081
+N44E082
+N44E083
+N44E084
+N44E085
+N44E086
+N44E087
+N44E088
+N44E089
+N44E090
+N44E091
+N44E092
+N44E093
+N44E094
+N44E095
+N44E096
+N44E097
+N44E098
+N44E099
+N44E100
+N44E101
+N44E102
+N44E103
+N44E104
+N44E105
+N44E106
+N44E107
+N44E108
+N44E109
+N44E110
+N44E111
+N44E112
+N44E113
+N44E114
+N44E115
+N44E116
+N44E117
+N44E118
+N44E119
+N44E120
+N44E121
+N44E122
+N44E123
+N44E124
+N44E125
+N44E126
+N44E127
+N44E128
+N44E129
+N44E130
+N44E131
+N44E132
+N44E133
+N44E134
+N44E135
+N44E136
+N44E141
+N44E142
+N44E143
+N44E144
+N44E145
+N44E146
+N44E147
+N44W001
+N44W002
+N45E000
+N45E001
+N45E002
+N45E003
+N45E004
+N45E005
+N45E006
+N45E007
+N45E008
+N45E009
+N45E010
+N45E011
+N45E012
+N45E013
+N45E014
+N45E015
+N45E016
+N45E017
+N45E018
+N45E019
+N45E020
+N45E021
+N45E022
+N45E023
+N45E024
+N45E025
+N45E026
+N45E027
+N45E028
+N45E029
+N45E030
+N45E032
+N45E033
+N45E034
+N45E035
+N45E036
+N45E037
+N45E038
+N45E039
+N45E040
+N45E041
+N45E042
+N45E043
+N45E044
+N45E045
+N45E046
+N45E047
+N45E048
+N45E049
+N45E050
+N45E051
+N45E052
+N45E053
+N45E054
+N45E055
+N45E056
+N45E057
+N45E058
+N45E059
+N45E060
+N45E061
+N45E062
+N45E063
+N45E064
+N45E065
+N45E066
+N45E067
+N45E068
+N45E069
+N45E070
+N45E071
+N45E072
+N45E073
+N45E074
+N45E075
+N45E076
+N45E077
+N45E078
+N45E079
+N45E080
+N45E081
+N45E082
+N45E083
+N45E084
+N45E085
+N45E086
+N45E087
+N45E088
+N45E089
+N45E090
+N45E091
+N45E092
+N45E093
+N45E094
+N45E095
+N45E096
+N45E097
+N45E098
+N45E099
+N45E100
+N45E101
+N45E102
+N45E103
+N45E104
+N45E105
+N45E106
+N45E107
+N45E108
+N45E109
+N45E110
+N45E111
+N45E112
+N45E113
+N45E114
+N45E115
+N45E116
+N45E117
+N45E118
+N45E119
+N45E120
+N45E121
+N45E122
+N45E123
+N45E124
+N45E125
+N45E126
+N45E127
+N45E128
+N45E129
+N45E130
+N45E131
+N45E132
+N45E133
+N45E134
+N45E135
+N45E136
+N45E137
+N45E140
+N45E141
+N45E142
+N45E147
+N45E148
+N45E149
+N45E150
+N45W001
+N45W002
+N46E000
+N46E001
+N46E002
+N46E003
+N46E004
+N46E005
+N46E006
+N46E007
+N46E008
+N46E009
+N46E010
+N46E011
+N46E012
+N46E013
+N46E014
+N46E015
+N46E016
+N46E017
+N46E018
+N46E019
+N46E020
+N46E021
+N46E022
+N46E023
+N46E024
+N46E025
+N46E026
+N46E027
+N46E028
+N46E029
+N46E030
+N46E031
+N46E032
+N46E033
+N46E034
+N46E035
+N46E036
+N46E037
+N46E038
+N46E039
+N46E040
+N46E041
+N46E042
+N46E043
+N46E044
+N46E045
+N46E046
+N46E047
+N46E048
+N46E049
+N46E050
+N46E051
+N46E052
+N46E053
+N46E054
+N46E055
+N46E056
+N46E057
+N46E058
+N46E059
+N46E060
+N46E061
+N46E062
+N46E063
+N46E064
+N46E065
+N46E066
+N46E067
+N46E068
+N46E069
+N46E070
+N46E071
+N46E072
+N46E073
+N46E074
+N46E075
+N46E076
+N46E077
+N46E078
+N46E079
+N46E080
+N46E081
+N46E082
+N46E083
+N46E084
+N46E085
+N46E086
+N46E087
+N46E088
+N46E089
+N46E090
+N46E091
+N46E092
+N46E093
+N46E094
+N46E095
+N46E096
+N46E097
+N46E098
+N46E099
+N46E100
+N46E101
+N46E102
+N46E103
+N46E104
+N46E105
+N46E106
+N46E107
+N46E108
+N46E109
+N46E110
+N46E111
+N46E112
+N46E113
+N46E114
+N46E115
+N46E116
+N46E117
+N46E118
+N46E119
+N46E120
+N46E121
+N46E122
+N46E123
+N46E124
+N46E125
+N46E126
+N46E127
+N46E128
+N46E129
+N46E130
+N46E131
+N46E132
+N46E133
+N46E134
+N46E135
+N46E136
+N46E137
+N46E138
+N46E141
+N46E142
+N46E143
+N46E149
+N46E150
+N46E151
+N46E152
+N46W001
+N46W002
+N46W003
+N47E000
+N47E001
+N47E002
+N47E003
+N47E004
+N47E005
+N47E006
+N47E007
+N47E008
+N47E009
+N47E010
+N47E011
+N47E012
+N47E013
+N47E014
+N47E015
+N47E016
+N47E017
+N47E018
+N47E019
+N47E020
+N47E021
+N47E022
+N47E023
+N47E024
+N47E025
+N47E026
+N47E027
+N47E028
+N47E029
+N47E030
+N47E031
+N47E032
+N47E033
+N47E034
+N47E035
+N47E036
+N47E037
+N47E038
+N47E039
+N47E040
+N47E041
+N47E042
+N47E043
+N47E044
+N47E045
+N47E046
+N47E047
+N47E048
+N47E049
+N47E050
+N47E051
+N47E052
+N47E053
+N47E054
+N47E055
+N47E056
+N47E057
+N47E058
+N47E059
+N47E060
+N47E061
+N47E062
+N47E063
+N47E064
+N47E065
+N47E066
+N47E067
+N47E068
+N47E069
+N47E070
+N47E071
+N47E072
+N47E073
+N47E074
+N47E075
+N47E076
+N47E077
+N47E078
+N47E079
+N47E080
+N47E081
+N47E082
+N47E083
+N47E084
+N47E085
+N47E086
+N47E087
+N47E088
+N47E089
+N47E090
+N47E091
+N47E092
+N47E093
+N47E094
+N47E095
+N47E096
+N47E097
+N47E098
+N47E099
+N47E100
+N47E101
+N47E102
+N47E103
+N47E104
+N47E105
+N47E106
+N47E107
+N47E108
+N47E109
+N47E110
+N47E111
+N47E112
+N47E113
+N47E114
+N47E115
+N47E116
+N47E117
+N47E118
+N47E119
+N47E120
+N47E121
+N47E122
+N47E123
+N47E124
+N47E125
+N47E126
+N47E127
+N47E128
+N47E129
+N47E130
+N47E131
+N47E132
+N47E133
+N47E134
+N47E135
+N47E136
+N47E137
+N47E138
+N47E139
+N47E141
+N47E142
+N47E143
+N47E152
+N47E153
+N47W001
+N47W002
+N47W003
+N47W004
+N47W005
+N48E000
+N48E001
+N48E002
+N48E003
+N48E004
+N48E005
+N48E006
+N48E007
+N48E008
+N48E009
+N48E010
+N48E011
+N48E012
+N48E013
+N48E014
+N48E015
+N48E016
+N48E017
+N48E018
+N48E019
+N48E020
+N48E021
+N48E022
+N48E023
+N48E024
+N48E025
+N48E026
+N48E027
+N48E028
+N48E029
+N48E030
+N48E031
+N48E032
+N48E033
+N48E034
+N48E035
+N48E036
+N48E037
+N48E038
+N48E039
+N48E040
+N48E041
+N48E042
+N48E043
+N48E044
+N48E045
+N48E046
+N48E047
+N48E048
+N48E049
+N48E050
+N48E051
+N48E052
+N48E053
+N48E054
+N48E055
+N48E056
+N48E057
+N48E058
+N48E059
+N48E060
+N48E061
+N48E062
+N48E063
+N48E064
+N48E065
+N48E066
+N48E067
+N48E068
+N48E069
+N48E070
+N48E071
+N48E072
+N48E073
+N48E074
+N48E075
+N48E076
+N48E077
+N48E078
+N48E079
+N48E080
+N48E081
+N48E082
+N48E083
+N48E084
+N48E085
+N48E086
+N48E087
+N48E088
+N48E089
+N48E090
+N48E091
+N48E092
+N48E093
+N48E094
+N48E095
+N48E096
+N48E097
+N48E098
+N48E099
+N48E100
+N48E101
+N48E102
+N48E103
+N48E104
+N48E105
+N48E106
+N48E107
+N48E108
+N48E109
+N48E110
+N48E111
+N48E112
+N48E113
+N48E114
+N48E115
+N48E116
+N48E117
+N48E118
+N48E119
+N48E120
+N48E121
+N48E122
+N48E123
+N48E124
+N48E125
+N48E126
+N48E127
+N48E128
+N48E129
+N48E130
+N48E131
+N48E132
+N48E133
+N48E134
+N48E135
+N48E136
+N48E137
+N48E138
+N48E139
+N48E140
+N48E141
+N48E142
+N48E144
+N48E153
+N48E154
+N48W001
+N48W002
+N48W003
+N48W004
+N48W005
+N48W006
+N49E000
+N49E001
+N49E002
+N49E003
+N49E004
+N49E005
+N49E006
+N49E007
+N49E008
+N49E009
+N49E010
+N49E011
+N49E012
+N49E013
+N49E014
+N49E015
+N49E016
+N49E017
+N49E018
+N49E019
+N49E020
+N49E021
+N49E022
+N49E023
+N49E024
+N49E025
+N49E026
+N49E027
+N49E028
+N49E029
+N49E030
+N49E031
+N49E032
+N49E033
+N49E034
+N49E035
+N49E036
+N49E037
+N49E038
+N49E039
+N49E040
+N49E041
+N49E042
+N49E043
+N49E044
+N49E045
+N49E046
+N49E047
+N49E048
+N49E049
+N49E050
+N49E051
+N49E052
+N49E053
+N49E054
+N49E055
+N49E056
+N49E057
+N49E058
+N49E059
+N49E060
+N49E061
+N49E062
+N49E063
+N49E064
+N49E065
+N49E066
+N49E067
+N49E068
+N49E069
+N49E070
+N49E071
+N49E072
+N49E073
+N49E074
+N49E075
+N49E076
+N49E077
+N49E078
+N49E079
+N49E080
+N49E081
+N49E082
+N49E083
+N49E084
+N49E085
+N49E086
+N49E087
+N49E088
+N49E089
+N49E090
+N49E091
+N49E092
+N49E093
+N49E094
+N49E095
+N49E096
+N49E097
+N49E098
+N49E099
+N49E100
+N49E101
+N49E102
+N49E103
+N49E104
+N49E105
+N49E106
+N49E107
+N49E108
+N49E109
+N49E110
+N49E111
+N49E112
+N49E113
+N49E114
+N49E115
+N49E116
+N49E117
+N49E118
+N49E119
+N49E120
+N49E121
+N49E122
+N49E123
+N49E124
+N49E125
+N49E126
+N49E127
+N49E128
+N49E129
+N49E130
+N49E131
+N49E132
+N49E133
+N49E134
+N49E135
+N49E136
+N49E137
+N49E138
+N49E139
+N49E140
+N49E142
+N49E143
+N49E144
+N49E154
+N49E155
+N49W001
+N49W002
+N49W003
+N49W006
+N49W007
+N50E000
+N50E001
+N50E002
+N50E003
+N50E004
+N50E005
+N50E006
+N50E007
+N50E008
+N50E009
+N50E010
+N50E011
+N50E012
+N50E013
+N50E014
+N50E015
+N50E016
+N50E017
+N50E018
+N50E019
+N50E020
+N50E021
+N50E022
+N50E023
+N50E024
+N50E025
+N50E026
+N50E027
+N50E028
+N50E029
+N50E030
+N50E031
+N50E032
+N50E033
+N50E034
+N50E035
+N50E036
+N50E037
+N50E038
+N50E039
+N50E040
+N50E041
+N50E042
+N50E043
+N50E044
+N50E045
+N50E046
+N50E047
+N50E048
+N50E049
+N50E050
+N50E051
+N50E052
+N50E053
+N50E054
+N50E055
+N50E056
+N50E057
+N50E058
+N50E059
+N50E060
+N50E061
+N50E062
+N50E063
+N50E064
+N50E065
+N50E066
+N50E067
+N50E068
+N50E069
+N50E070
+N50E071
+N50E072
+N50E073
+N50E074
+N50E075
+N50E076
+N50E077
+N50E078
+N50E079
+N50E080
+N50E081
+N50E082
+N50E083
+N50E084
+N50E085
+N50E086
+N50E087
+N50E088
+N50E089
+N50E090
+N50E091
+N50E092
+N50E093
+N50E094
+N50E095
+N50E096
+N50E097
+N50E098
+N50E099
+N50E100
+N50E101
+N50E102
+N50E103
+N50E104
+N50E105
+N50E106
+N50E107
+N50E108
+N50E109
+N50E110
+N50E111
+N50E112
+N50E113
+N50E114
+N50E115
+N50E116
+N50E117
+N50E118
+N50E119
+N50E120
+N50E121
+N50E122
+N50E123
+N50E124
+N50E125
+N50E126
+N50E127
+N50E128
+N50E129
+N50E130
+N50E131
+N50E132
+N50E133
+N50E134
+N50E135
+N50E136
+N50E137
+N50E138
+N50E139
+N50E140
+N50E142
+N50E143
+N50E154
+N50E155
+N50E156
+N50W001
+N50W002
+N50W003
+N50W004
+N50W005
+N50W006
+N51E000
+N51E001
+N51E002
+N51E003
+N51E004
+N51E005
+N51E006
+N51E007
+N51E008
+N51E009
+N51E010
+N51E011
+N51E012
+N51E013
+N51E014
+N51E015
+N51E016
+N51E017
+N51E018
+N51E019
+N51E020
+N51E021
+N51E022
+N51E023
+N51E024
+N51E025
+N51E026
+N51E027
+N51E028
+N51E029
+N51E030
+N51E031
+N51E032
+N51E033
+N51E034
+N51E035
+N51E036
+N51E037
+N51E038
+N51E039
+N51E040
+N51E041
+N51E042
+N51E043
+N51E044
+N51E045
+N51E046
+N51E047
+N51E048
+N51E049
+N51E050
+N51E051
+N51E052
+N51E053
+N51E054
+N51E055
+N51E056
+N51E057
+N51E058
+N51E059
+N51E060
+N51E061
+N51E062
+N51E063
+N51E064
+N51E065
+N51E066
+N51E067
+N51E068
+N51E069
+N51E070
+N51E071
+N51E072
+N51E073
+N51E074
+N51E075
+N51E076
+N51E077
+N51E078
+N51E079
+N51E080
+N51E081
+N51E082
+N51E083
+N51E084
+N51E085
+N51E086
+N51E087
+N51E088
+N51E089
+N51E090
+N51E091
+N51E092
+N51E093
+N51E094
+N51E095
+N51E096
+N51E097
+N51E098
+N51E099
+N51E100
+N51E101
+N51E102
+N51E103
+N51E104
+N51E105
+N51E106
+N51E107
+N51E108
+N51E109
+N51E110
+N51E111
+N51E112
+N51E113
+N51E114
+N51E115
+N51E116
+N51E117
+N51E118
+N51E119
+N51E120
+N51E121
+N51E122
+N51E123
+N51E124
+N51E125
+N51E126
+N51E127
+N51E128
+N51E129
+N51E130
+N51E131
+N51E132
+N51E133
+N51E134
+N51E135
+N51E136
+N51E137
+N51E138
+N51E139
+N51E140
+N51E141
+N51E142
+N51E143
+N51E156
+N51E157
+N51E158
+N51W001
+N51W002
+N51W003
+N51W004
+N51W005
+N51W006
+N51W008
+N51W009
+N51W010
+N51W011
+N52E000
+N52E001
+N52E004
+N52E005
+N52E006
+N52E007
+N52E008
+N52E009
+N52E010
+N52E011
+N52E012
+N52E013
+N52E014
+N52E015
+N52E016
+N52E017
+N52E018
+N52E019
+N52E020
+N52E021
+N52E022
+N52E023
+N52E024
+N52E025
+N52E026
+N52E027
+N52E028
+N52E029
+N52E030
+N52E031
+N52E032
+N52E033
+N52E034
+N52E035
+N52E036
+N52E037
+N52E038
+N52E039
+N52E040
+N52E041
+N52E042
+N52E043
+N52E044
+N52E045
+N52E046
+N52E047
+N52E048
+N52E049
+N52E050
+N52E051
+N52E052
+N52E053
+N52E054
+N52E055
+N52E056
+N52E057
+N52E058
+N52E059
+N52E060
+N52E061
+N52E062
+N52E063
+N52E064
+N52E065
+N52E066
+N52E067
+N52E068
+N52E069
+N52E070
+N52E071
+N52E072
+N52E073
+N52E074
+N52E075
+N52E076
+N52E077
+N52E078
+N52E079
+N52E080
+N52E081
+N52E082
+N52E083
+N52E084
+N52E085
+N52E086
+N52E087
+N52E088
+N52E089
+N52E090
+N52E091
+N52E092
+N52E093
+N52E094
+N52E095
+N52E096
+N52E097
+N52E098
+N52E099
+N52E100
+N52E101
+N52E102
+N52E103
+N52E104
+N52E105
+N52E106
+N52E107
+N52E108
+N52E109
+N52E110
+N52E111
+N52E112
+N52E113
+N52E114
+N52E115
+N52E116
+N52E117
+N52E118
+N52E119
+N52E120
+N52E121
+N52E122
+N52E123
+N52E124
+N52E125
+N52E126
+N52E127
+N52E128
+N52E129
+N52E130
+N52E131
+N52E132
+N52E133
+N52E134
+N52E135
+N52E136
+N52E137
+N52E138
+N52E139
+N52E140
+N52E141
+N52E142
+N52E143
+N52E156
+N52E157
+N52E158
+N52W001
+N52W002
+N52W003
+N52W004
+N52W005
+N52W006
+N52W007
+N52W008
+N52W009
+N52W010
+N52W011
+N53E000
+N53E004
+N53E005
+N53E006
+N53E007
+N53E008
+N53E009
+N53E010
+N53E011
+N53E012
+N53E013
+N53E014
+N53E015
+N53E016
+N53E017
+N53E018
+N53E019
+N53E020
+N53E021
+N53E022
+N53E023
+N53E024
+N53E025
+N53E026
+N53E027
+N53E028
+N53E029
+N53E030
+N53E031
+N53E032
+N53E033
+N53E034
+N53E035
+N53E036
+N53E037
+N53E038
+N53E039
+N53E040
+N53E041
+N53E042
+N53E043
+N53E044
+N53E045
+N53E046
+N53E047
+N53E048
+N53E049
+N53E050
+N53E051
+N53E052
+N53E053
+N53E054
+N53E055
+N53E056
+N53E057
+N53E058
+N53E059
+N53E060
+N53E061
+N53E062
+N53E063
+N53E064
+N53E065
+N53E066
+N53E067
+N53E068
+N53E069
+N53E070
+N53E071
+N53E072
+N53E073
+N53E074
+N53E075
+N53E076
+N53E077
+N53E078
+N53E079
+N53E080
+N53E081
+N53E082
+N53E083
+N53E084
+N53E085
+N53E086
+N53E087
+N53E088
+N53E089
+N53E090
+N53E091
+N53E092
+N53E093
+N53E094
+N53E095
+N53E096
+N53E097
+N53E098
+N53E099
+N53E100
+N53E101
+N53E102
+N53E103
+N53E104
+N53E105
+N53E106
+N53E107
+N53E108
+N53E109
+N53E110
+N53E111
+N53E112
+N53E113
+N53E114
+N53E115
+N53E116
+N53E117
+N53E118
+N53E119
+N53E120
+N53E121
+N53E122
+N53E123
+N53E124
+N53E125
+N53E126
+N53E127
+N53E128
+N53E129
+N53E130
+N53E131
+N53E132
+N53E133
+N53E134
+N53E135
+N53E136
+N53E137
+N53E138
+N53E139
+N53E140
+N53E141
+N53E142
+N53E143
+N53E155
+N53E156
+N53E157
+N53E158
+N53E159
+N53E160
+N53W001
+N53W002
+N53W003
+N53W004
+N53W005
+N53W006
+N53W007
+N53W008
+N53W009
+N53W010
+N53W011
+N54E007
+N54E008
+N54E009
+N54E010
+N54E011
+N54E012
+N54E013
+N54E014
+N54E015
+N54E016
+N54E017
+N54E018
+N54E019
+N54E020
+N54E021
+N54E022
+N54E023
+N54E024
+N54E025
+N54E026
+N54E027
+N54E028
+N54E029
+N54E030
+N54E031
+N54E032
+N54E033
+N54E034
+N54E035
+N54E036
+N54E037
+N54E038
+N54E039
+N54E040
+N54E041
+N54E042
+N54E043
+N54E044
+N54E045
+N54E046
+N54E047
+N54E048
+N54E049
+N54E050
+N54E051
+N54E052
+N54E053
+N54E054
+N54E055
+N54E056
+N54E057
+N54E058
+N54E059
+N54E060
+N54E061
+N54E062
+N54E063
+N54E064
+N54E065
+N54E066
+N54E067
+N54E068
+N54E069
+N54E070
+N54E071
+N54E072
+N54E073
+N54E074
+N54E075
+N54E076
+N54E077
+N54E078
+N54E079
+N54E080
+N54E081
+N54E082
+N54E083
+N54E084
+N54E085
+N54E086
+N54E087
+N54E088
+N54E089
+N54E090
+N54E091
+N54E092
+N54E093
+N54E094
+N54E095
+N54E096
+N54E097
+N54E098
+N54E099
+N54E100
+N54E101
+N54E102
+N54E103
+N54E104
+N54E105
+N54E106
+N54E107
+N54E108
+N54E109
+N54E110
+N54E111
+N54E112
+N54E113
+N54E114
+N54E115
+N54E116
+N54E117
+N54E118
+N54E119
+N54E120
+N54E121
+N54E122
+N54E123
+N54E124
+N54E125
+N54E126
+N54E127
+N54E128
+N54E129
+N54E130
+N54E131
+N54E132
+N54E133
+N54E134
+N54E135
+N54E136
+N54E137
+N54E138
+N54E139
+N54E140
+N54E142
+N54E155
+N54E156
+N54E157
+N54E158
+N54E159
+N54E160
+N54E161
+N54E162
+N54E166
+N54E167
+N54E168
+N54W001
+N54W002
+N54W003
+N54W004
+N54W005
+N54W006
+N54W007
+N54W008
+N54W009
+N54W010
+N54W011
+N55E008
+N55E009
+N55E010
+N55E011
+N55E012
+N55E013
+N55E014
+N55E015
+N55E020
+N55E021
+N55E022
+N55E023
+N55E024
+N55E025
+N55E026
+N55E027
+N55E028
+N55E029
+N55E030
+N55E031
+N55E032
+N55E033
+N55E034
+N55E035
+N55E036
+N55E037
+N55E038
+N55E039
+N55E040
+N55E041
+N55E042
+N55E043
+N55E044
+N55E045
+N55E046
+N55E047
+N55E048
+N55E049
+N55E050
+N55E051
+N55E052
+N55E053
+N55E054
+N55E055
+N55E056
+N55E057
+N55E058
+N55E059
+N55E060
+N55E061
+N55E062
+N55E063
+N55E064
+N55E065
+N55E066
+N55E067
+N55E068
+N55E069
+N55E070
+N55E071
+N55E072
+N55E073
+N55E074
+N55E075
+N55E076
+N55E077
+N55E078
+N55E079
+N55E080
+N55E081
+N55E082
+N55E083
+N55E084
+N55E085
+N55E086
+N55E087
+N55E088
+N55E089
+N55E090
+N55E091
+N55E092
+N55E093
+N55E094
+N55E095
+N55E096
+N55E097
+N55E098
+N55E099
+N55E100
+N55E101
+N55E102
+N55E103
+N55E104
+N55E105
+N55E106
+N55E107
+N55E108
+N55E109
+N55E110
+N55E111
+N55E112
+N55E113
+N55E114
+N55E115
+N55E116
+N55E117
+N55E118
+N55E119
+N55E120
+N55E121
+N55E122
+N55E123
+N55E124
+N55E125
+N55E126
+N55E127
+N55E128
+N55E129
+N55E130
+N55E131
+N55E132
+N55E133
+N55E134
+N55E135
+N55E136
+N55E137
+N55E138
+N55E155
+N55E156
+N55E157
+N55E158
+N55E159
+N55E160
+N55E161
+N55E162
+N55E165
+N55E166
+N55W002
+N55W003
+N55W004
+N55W005
+N55W006
+N55W007
+N55W008
+N55W009
+N56E008
+N56E009
+N56E010
+N56E011
+N56E012
+N56E013
+N56E014
+N56E015
+N56E016
+N56E018
+N56E020
+N56E021
+N56E022
+N56E023
+N56E024
+N56E025
+N56E026
+N56E027
+N56E028
+N56E029
+N56E030
+N56E031
+N56E032
+N56E033
+N56E034
+N56E035
+N56E036
+N56E037
+N56E038
+N56E039
+N56E040
+N56E041
+N56E042
+N56E043
+N56E044
+N56E045
+N56E046
+N56E047
+N56E048
+N56E049
+N56E050
+N56E051
+N56E052
+N56E053
+N56E054
+N56E055
+N56E056
+N56E057
+N56E058
+N56E059
+N56E060
+N56E061
+N56E062
+N56E063
+N56E064
+N56E065
+N56E066
+N56E067
+N56E068
+N56E069
+N56E070
+N56E071
+N56E072
+N56E073
+N56E074
+N56E075
+N56E076
+N56E077
+N56E078
+N56E079
+N56E080
+N56E081
+N56E082
+N56E083
+N56E084
+N56E085
+N56E086
+N56E087
+N56E088
+N56E089
+N56E090
+N56E091
+N56E092
+N56E093
+N56E094
+N56E095
+N56E096
+N56E097
+N56E098
+N56E099
+N56E100
+N56E101
+N56E102
+N56E103
+N56E104
+N56E105
+N56E106
+N56E107
+N56E108
+N56E109
+N56E110
+N56E111
+N56E112
+N56E113
+N56E114
+N56E115
+N56E116
+N56E117
+N56E118
+N56E119
+N56E120
+N56E121
+N56E122
+N56E123
+N56E124
+N56E125
+N56E126
+N56E127
+N56E128
+N56E129
+N56E130
+N56E131
+N56E132
+N56E133
+N56E134
+N56E135
+N56E136
+N56E137
+N56E138
+N56E143
+N56E155
+N56E156
+N56E157
+N56E158
+N56E159
+N56E160
+N56E161
+N56E162
+N56E163
+N56W003
+N56W004
+N56W005
+N56W006
+N56W007
+N56W008
+N57E006
+N57E007
+N57E008
+N57E009
+N57E010
+N57E011
+N57E012
+N57E013
+N57E014
+N57E015
+N57E016
+N57E017
+N57E018
+N57E019
+N57E021
+N57E022
+N57E023
+N57E024
+N57E025
+N57E026
+N57E027
+N57E028
+N57E029
+N57E030
+N57E031
+N57E032
+N57E033
+N57E034
+N57E035
+N57E036
+N57E037
+N57E038
+N57E039
+N57E040
+N57E041
+N57E042
+N57E043
+N57E044
+N57E045
+N57E046
+N57E047
+N57E048
+N57E049
+N57E050
+N57E051
+N57E052
+N57E053
+N57E054
+N57E055
+N57E056
+N57E057
+N57E058
+N57E059
+N57E060
+N57E061
+N57E062
+N57E063
+N57E064
+N57E065
+N57E066
+N57E067
+N57E068
+N57E069
+N57E070
+N57E071
+N57E072
+N57E073
+N57E074
+N57E075
+N57E076
+N57E077
+N57E078
+N57E079
+N57E080
+N57E081
+N57E082
+N57E083
+N57E084
+N57E085
+N57E086
+N57E087
+N57E088
+N57E089
+N57E090
+N57E091
+N57E092
+N57E093
+N57E094
+N57E095
+N57E096
+N57E097
+N57E098
+N57E099
+N57E100
+N57E101
+N57E102
+N57E103
+N57E104
+N57E105
+N57E106
+N57E107
+N57E108
+N57E109
+N57E110
+N57E111
+N57E112
+N57E113
+N57E114
+N57E115
+N57E116
+N57E117
+N57E118
+N57E119
+N57E120
+N57E121
+N57E122
+N57E123
+N57E124
+N57E125
+N57E126
+N57E127
+N57E128
+N57E129
+N57E130
+N57E131
+N57E132
+N57E133
+N57E134
+N57E135
+N57E136
+N57E137
+N57E138
+N57E139
+N57E140
+N57E156
+N57E157
+N57E158
+N57E159
+N57E160
+N57E161
+N57E162
+N57E163
+N57W002
+N57W003
+N57W004
+N57W005
+N57W006
+N57W007
+N57W008
+N57W009
+N57W014
+N58E005
+N58E006
+N58E007
+N58E008
+N58E009
+N58E010
+N58E011
+N58E012
+N58E013
+N58E014
+N58E015
+N58E016
+N58E017
+N58E018
+N58E019
+N58E021
+N58E022
+N58E023
+N58E024
+N58E025
+N58E026
+N58E027
+N58E028
+N58E029
+N58E030
+N58E031
+N58E032
+N58E033
+N58E034
+N58E035
+N58E036
+N58E037
+N58E038
+N58E039
+N58E040
+N58E041
+N58E042
+N58E043
+N58E044
+N58E045
+N58E046
+N58E047
+N58E048
+N58E049
+N58E050
+N58E051
+N58E052
+N58E053
+N58E054
+N58E055
+N58E056
+N58E057
+N58E058
+N58E059
+N58E060
+N58E061
+N58E062
+N58E063
+N58E064
+N58E065
+N58E066
+N58E067
+N58E068
+N58E069
+N58E070
+N58E071
+N58E072
+N58E073
+N58E074
+N58E075
+N58E076
+N58E077
+N58E078
+N58E079
+N58E080
+N58E081
+N58E082
+N58E083
+N58E084
+N58E085
+N58E086
+N58E087
+N58E088
+N58E089
+N58E090
+N58E091
+N58E092
+N58E093
+N58E094
+N58E095
+N58E096
+N58E097
+N58E098
+N58E099
+N58E100
+N58E101
+N58E102
+N58E103
+N58E104
+N58E105
+N58E106
+N58E107
+N58E108
+N58E109
+N58E110
+N58E111
+N58E112
+N58E113
+N58E114
+N58E115
+N58E116
+N58E117
+N58E118
+N58E119
+N58E120
+N58E121
+N58E122
+N58E123
+N58E124
+N58E125
+N58E126
+N58E127
+N58E128
+N58E129
+N58E130
+N58E131
+N58E132
+N58E133
+N58E134
+N58E135
+N58E136
+N58E137
+N58E138
+N58E139
+N58E140
+N58E141
+N58E142
+N58E150
+N58E151
+N58E152
+N58E157
+N58E158
+N58E159
+N58E160
+N58E161
+N58E162
+N58E163
+N58E164
+N58W003
+N58W004
+N58W005
+N58W006
+N58W007
+N58W008
+N59E004
+N59E005
+N59E006
+N59E007
+N59E008
+N59E009
+N59E010
+N59E011
+N59E012
+N59E013
+N59E014
+N59E015
+N59E016
+N59E017
+N59E018
+N59E019
+N59E020
+N59E021
+N59E022
+N59E023
+N59E024
+N59E025
+N59E026
+N59E027
+N59E028
+N59E029
+N59E030
+N59E031
+N59E032
+N59E033
+N59E034
+N59E035
+N59E036
+N59E037
+N59E038
+N59E039
+N59E040
+N59E041
+N59E042
+N59E043
+N59E044
+N59E045
+N59E046
+N59E047
+N59E048
+N59E049
+N59E050
+N59E051
+N59E052
+N59E053
+N59E054
+N59E055
+N59E056
+N59E057
+N59E058
+N59E059
+N59E060
+N59E061
+N59E062
+N59E063
+N59E064
+N59E065
+N59E066
+N59E067
+N59E068
+N59E069
+N59E070
+N59E071
+N59E072
+N59E073
+N59E074
+N59E075
+N59E076
+N59E077
+N59E078
+N59E079
+N59E080
+N59E081
+N59E082
+N59E083
+N59E084
+N59E085
+N59E086
+N59E087
+N59E088
+N59E089
+N59E090
+N59E091
+N59E092
+N59E093
+N59E094
+N59E095
+N59E096
+N59E097
+N59E098
+N59E099
+N59E100
+N59E101
+N59E102
+N59E103
+N59E104
+N59E105
+N59E106
+N59E107
+N59E108
+N59E109
+N59E110
+N59E111
+N59E112
+N59E113
+N59E114
+N59E115
+N59E116
+N59E117
+N59E118
+N59E119
+N59E120
+N59E121
+N59E122
+N59E123
+N59E124
+N59E125
+N59E126
+N59E127
+N59E128
+N59E129
+N59E130
+N59E131
+N59E132
+N59E133
+N59E134
+N59E135
+N59E136
+N59E137
+N59E138
+N59E139
+N59E140
+N59E141
+N59E142
+N59E143
+N59E144
+N59E145
+N59E146
+N59E147
+N59E148
+N59E149
+N59E150
+N59E151
+N59E152
+N59E153
+N59E154
+N59E155
+N59E159
+N59E160
+N59E161
+N59E162
+N59E163
+N59E164
+N59E165
+N59E166
+N59W002
+N59W003
+N59W004
+N59W005
+N59W006
+N59W007
+N60E004
+N60E005
+N60E006
+N60E007
+N60E008
+N60E009
+N60E010
+N60E011
+N60E012
+N60E013
+N60E014
+N60E015
+N60E016
+N60E017
+N60E018
+N60E019
+N60E020
+N60E021
+N60E022
+N60E023
+N60E024
+N60E025
+N60E026
+N60E027
+N60E028
+N60E029
+N60E030
+N60E031
+N60E032
+N60E033
+N60E034
+N60E035
+N60E036
+N60E037
+N60E038
+N60E039
+N60E040
+N60E041
+N60E042
+N60E043
+N60E044
+N60E045
+N60E046
+N60E047
+N60E048
+N60E049
+N60E050
+N60E051
+N60E052
+N60E053
+N60E054
+N60E055
+N60E056
+N60E057
+N60E058
+N60E059
+N60E060
+N60E061
+N60E062
+N60E063
+N60E064
+N60E065
+N60E066
+N60E067
+N60E068
+N60E069
+N60E070
+N60E071
+N60E072
+N60E073
+N60E074
+N60E075
+N60E076
+N60E077
+N60E078
+N60E079
+N60E080
+N60E081
+N60E082
+N60E083
+N60E084
+N60E085
+N60E086
+N60E087
+N60E088
+N60E089
+N60E090
+N60E091
+N60E092
+N60E093
+N60E094
+N60E095
+N60E096
+N60E097
+N60E098
+N60E099
+N60E100
+N60E101
+N60E102
+N60E103
+N60E104
+N60E105
+N60E106
+N60E107
+N60E108
+N60E109
+N60E110
+N60E111
+N60E112
+N60E113
+N60E114
+N60E115
+N60E116
+N60E117
+N60E118
+N60E119
+N60E120
+N60E121
+N60E122
+N60E123
+N60E124
+N60E125
+N60E126
+N60E127
+N60E128
+N60E129
+N60E130
+N60E131
+N60E132
+N60E133
+N60E134
+N60E135
+N60E136
+N60E137
+N60E138
+N60E139
+N60E140
+N60E141
+N60E142
+N60E143
+N60E144
+N60E145
+N60E146
+N60E147
+N60E148
+N60E149
+N60E150
+N60E151
+N60E152
+N60E153
+N60E154
+N60E155
+N60E156
+N60E159
+N60E160
+N60E161
+N60E162
+N60E163
+N60E164
+N60E165
+N60E166
+N60E167
+N60E168
+N60E169
+N60E170
+N60E171
+N60E172
+N60W001
+N60W002
+N60W003
+S01E073
+S01E098
+S01E099
+S01E100
+S01E101
+S01E102
+S01E103
+S01E104
+S01E105
+S01E109
+S01E110
+S01E111
+S01E112
+S01E113
+S01E114
+S01E115
+S01E116
+S01E117
+S01E119
+S01E120
+S01E121
+S01E122
+S01E123
+S01E127
+S01E128
+S01E129
+S01E130
+S01E131
+S01E132
+S01E133
+S01E134
+S01E135
+S01E136
+S01E145
+S01E166
+S01E169
+S01E174
+S01W161
+S02E098
+S02E099
+S02E100
+S02E101
+S02E102
+S02E103
+S02E104
+S02E105
+S02E106
+S02E108
+S02E109
+S02E110
+S02E111
+S02E112
+S02E113
+S02E114
+S02E115
+S02E116
+S02E117
+S02E119
+S02E120
+S02E121
+S02E122
+S02E123
+S02E124
+S02E125
+S02E126
+S02E127
+S02E128
+S02E129
+S02E130
+S02E131
+S02E132
+S02E133
+S02E134
+S02E135
+S02E136
+S02E137
+S02E138
+S02E139
+S02E142
+S02E143
+S02E144
+S02E145
+S02E146
+S02E147
+S02E148
+S02E149
+S02E150
+S02E174
+S02E175
+S02E176
+S03E099
+S03E100
+S03E101
+S03E102
+S03E103
+S03E104
+S03E105
+S03E106
+S03E107
+S03E108
+S03E110
+S03E111
+S03E112
+S03E113
+S03E114
+S03E115
+S03E116
+S03E117
+S03E118
+S03E119
+S03E120
+S03E121
+S03E122
+S03E123
+S03E124
+S03E125
+S03E126
+S03E127
+S03E128
+S03E129
+S03E130
+S03E131
+S03E132
+S03E133
+S03E134
+S03E135
+S03E136
+S03E137
+S03E138
+S03E139
+S03E140
+S03E141
+S03E142
+S03E145
+S03E146
+S03E147
+S03E148
+S03E149
+S03E150
+S03E151
+S03E152
+S03E175
+S03E176
+S03W172
+S04E100
+S04E101
+S04E102
+S04E103
+S04E104
+S04E105
+S04E106
+S04E107
+S04E108
+S04E110
+S04E111
+S04E112
+S04E113
+S04E114
+S04E115
+S04E116
+S04E117
+S04E118
+S04E119
+S04E120
+S04E121
+S04E122
+S04E123
+S04E125
+S04E126
+S04E127
+S04E128
+S04E129
+S04E130
+S04E131
+S04E132
+S04E133
+S04E134
+S04E135
+S04E136
+S04E137
+S04E138
+S04E139
+S04E140
+S04E141
+S04E142
+S04E143
+S04E144
+S04E150
+S04E151
+S04E152
+S04E153
+S04E154
+S04W155
+S04W171
+S04W172
+S04W175
+S05E101
+S05E102
+S05E103
+S05E104
+S05E105
+S05E114
+S05E115
+S05E116
+S05E119
+S05E120
+S05E121
+S05E122
+S05E123
+S05E129
+S05E130
+S05E131
+S05E132
+S05E133
+S05E134
+S05E135
+S05E136
+S05E137
+S05E138
+S05E139
+S05E140
+S05E141
+S05E142
+S05E143
+S05E144
+S05E145
+S05E146
+S05E149
+S05E150
+S05E151
+S05E152
+S05E153
+S05E154
+S05E155
+S05E156
+S05E157
+S05E159
+S05W155
+S05W172
+S05W173
+S05W175
+S06E071
+S06E072
+S06E102
+S06E103
+S06E104
+S06E105
+S06E106
+S06E107
+S06E108
+S06E110
+S06E112
+S06E114
+S06E117
+S06E118
+S06E119
+S06E120
+S06E121
+S06E122
+S06E123
+S06E124
+S06E127
+S06E130
+S06E131
+S06E132
+S06E133
+S06E134
+S06E137
+S06E138
+S06E139
+S06E140
+S06E141
+S06E142
+S06E143
+S06E144
+S06E145
+S06E146
+S06E147
+S06E148
+S06E149
+S06E150
+S06E151
+S06E152
+S06E154
+S06E155
+S06E159
+S06E176
+S06W156
+S07E071
+S07E105
+S07E106
+S07E107
+S07E108
+S07E109
+S07E110
+S07E111
+S07E112
+S07E113
+S07E114
+S07E115
+S07E116
+S07E118
+S07E119
+S07E120
+S07E121
+S07E122
+S07E124
+S07E126
+S07E129
+S07E130
+S07E131
+S07E132
+S07E134
+S07E138
+S07E139
+S07E140
+S07E141
+S07E142
+S07E143
+S07E144
+S07E145
+S07E146
+S07E147
+S07E148
+S07E149
+S07E150
+S07E151
+S07E154
+S07E155
+S07E156
+S07E157
+S07E176
+S07E177
+S08E072
+S08E105
+S08E106
+S08E107
+S08E108
+S08E109
+S08E110
+S08E111
+S08E112
+S08E113
+S08E114
+S08E115
+S08E117
+S08E118
+S08E120
+S08E121
+S08E122
+S08E123
+S08E125
+S08E126
+S08E127
+S08E128
+S08E129
+S08E130
+S08E131
+S08E134
+S08E137
+S08E138
+S08E139
+S08E140
+S08E141
+S08E142
+S08E143
+S08E144
+S08E145
+S08E146
+S08E147
+S08E155
+S08E156
+S08E157
+S08E158
+S08E159
+S08E160
+S08E177
+S08E178
+S08W141
+S09E110
+S09E111
+S09E112
+S09E113
+S09E114
+S09E115
+S09E116
+S09E117
+S09E118
+S09E119
+S09E120
+S09E121
+S09E122
+S09E123
+S09E124
+S09E125
+S09E126
+S09E127
+S09E128
+S09E129
+S09E130
+S09E131
+S09E137
+S09E138
+S09E139
+S09E140
+S09E141
+S09E142
+S09E143
+S09E145
+S09E146
+S09E147
+S09E148
+S09E149
+S09E150
+S09E151
+S09E152
+S09E156
+S09E157
+S09E158
+S09E159
+S09E160
+S09E161
+S09E178
+S09E179
+S09W140
+S09W141
+S09W158
+S09W159
+S09W173
+S10E116
+S10E117
+S10E118
+S10E119
+S10E120
+S10E123
+S10E124
+S10E125
+S10E126
+S10E140
+S10E141
+S10E142
+S10E143
+S10E144
+S10E146
+S10E147
+S10E148
+S10E149
+S10E150
+S10E151
+S10E152
+S10E153
+S10E158
+S10E159
+S10E160
+S10E161
+S10E167
+S10E179
+S10W139
+S10W140
+S10W141
+S10W151
+S10W158
+S10W159
+S10W162
+S10W172
+S11E105
+S12E096
+S13E096
+
diff --git a/tim/prune/function/srtm/gen/tiles2.txt b/tim/prune/function/srtm/gen/tiles2.txt
new file mode 100644 (file)
index 0000000..f60c70b
--- /dev/null
@@ -0,0 +1,1917 @@
+North_America
+N10W110
+N15W062
+N15W064
+N15W079
+N15W080
+N15W083
+N15W084
+N15W085
+N15W086
+N15W087
+N15W088
+N15W089
+N15W090
+N15W091
+N15W092
+N15W093
+N15W094
+N15W096
+N15W097
+N15W098
+N16W062
+N16W063
+N16W086
+N16W087
+N16W088
+N16W089
+N16W090
+N16W091
+N16W092
+N16W093
+N16W094
+N16W095
+N16W096
+N16W097
+N16W098
+N16W099
+N16W100
+N16W101
+N17W062
+N17W063
+N17W064
+N17W065
+N17W066
+N17W067
+N17W068
+N17W072
+N17W076
+N17W077
+N17W078
+N17W084
+N17W088
+N17W089
+N17W090
+N17W091
+N17W092
+N17W093
+N17W094
+N17W095
+N17W096
+N17W097
+N17W098
+N17W099
+N17W100
+N17W101
+N17W102
+N17W103
+N18W063
+N18W064
+N18W065
+N18W066
+N18W067
+N18W068
+N18W069
+N18W070
+N18W071
+N18W072
+N18W073
+N18W074
+N18W075
+N18W076
+N18W077
+N18W078
+N18W079
+N18W088
+N18W089
+N18W090
+N18W091
+N18W092
+N18W093
+N18W094
+N18W095
+N18W096
+N18W097
+N18W098
+N18W099
+N18W100
+N18W101
+N18W102
+N18W103
+N18W104
+N18W105
+N18W111
+N18W112
+N18W115
+N19W069
+N19W070
+N19W071
+N19W072
+N19W073
+N19W074
+N19W075
+N19W076
+N19W077
+N19W078
+N19W080
+N19W081
+N19W082
+N19W088
+N19W089
+N19W090
+N19W091
+N19W092
+N19W096
+N19W097
+N19W098
+N19W099
+N19W100
+N19W101
+N19W102
+N19W103
+N19W104
+N19W105
+N19W106
+N19W111
+N20W073
+N20W074
+N20W075
+N20W076
+N20W077
+N20W078
+N20W079
+N20W080
+N20W087
+N20W088
+N20W089
+N20W090
+N20W091
+N20W092
+N20W093
+N20W097
+N20W098
+N20W099
+N20W100
+N20W101
+N20W102
+N20W103
+N20W104
+N20W105
+N20W106
+N21W072
+N21W073
+N21W074
+N21W076
+N21W077
+N21W078
+N21W079
+N21W080
+N21W081
+N21W082
+N21W083
+N21W084
+N21W085
+N21W087
+N21W088
+N21W089
+N21W090
+N21W091
+N21W098
+N21W099
+N21W100
+N21W101
+N21W102
+N21W103
+N21W104
+N21W105
+N21W106
+N21W107
+N22W073
+N22W074
+N22W075
+N22W076
+N22W078
+N22W079
+N22W080
+N22W081
+N22W082
+N22W083
+N22W084
+N22W085
+N22W090
+N22W092
+N22W098
+N22W099
+N22W100
+N22W101
+N22W102
+N22W103
+N22W104
+N22W105
+N22W106
+N22W107
+N22W110
+N22W111
+N23W074
+N23W075
+N23W076
+N23W077
+N23W078
+N23W080
+N23W081
+N23W082
+N23W083
+N23W084
+N23W098
+N23W099
+N23W100
+N23W101
+N23W102
+N23W103
+N23W104
+N23W105
+N23W106
+N23W107
+N23W108
+N23W110
+N23W111
+N24W075
+N24W076
+N24W077
+N24W078
+N24W079
+N24W080
+N24W081
+N24W082
+N24W083
+N24W098
+N24W099
+N24W100
+N24W101
+N24W102
+N24W103
+N24W104
+N24W105
+N24W106
+N24W107
+N24W108
+N24W109
+N24W110
+N24W111
+N24W112
+N24W113
+N24W116
+N25W077
+N25W078
+N25W079
+N25W080
+N25W081
+N25W082
+N25W098
+N25W099
+N25W100
+N25W101
+N25W102
+N25W103
+N25W104
+N25W105
+N25W106
+N25W107
+N25W108
+N25W109
+N25W110
+N25W111
+N25W112
+N25W113
+N26W077
+N26W078
+N26W079
+N26W080
+N26W081
+N26W082
+N26W083
+N26W098
+N26W099
+N26W100
+N26W101
+N26W102
+N26W103
+N26W104
+N26W105
+N26W106
+N26W107
+N26W108
+N26W109
+N26W110
+N26W112
+N26W113
+N26W114
+N26W115
+N27W078
+N27W079
+N27W081
+N27W082
+N27W083
+N27W097
+N27W098
+N27W099
+N27W100
+N27W101
+N27W102
+N27W103
+N27W104
+N27W105
+N27W106
+N27W107
+N27W108
+N27W109
+N27W110
+N27W111
+N27W112
+N27W113
+N27W114
+N27W115
+N27W116
+N28W081
+N28W082
+N28W083
+N28W090
+N28W096
+N28W097
+N28W098
+N28W099
+N28W100
+N28W101
+N28W102
+N28W103
+N28W104
+N28W105
+N28W106
+N28W107
+N28W108
+N28W109
+N28W110
+N28W111
+N28W112
+N28W113
+N28W114
+N28W115
+N28W116
+N28W119
+N29W081
+N29W082
+N29W083
+N29W084
+N29W085
+N29W086
+N29W089
+N29W090
+N29W091
+N29W092
+N29W093
+N29W094
+N29W095
+N29W096
+N29W097
+N29W098
+N29W099
+N29W100
+N29W101
+N29W102
+N29W103
+N29W104
+N29W105
+N29W106
+N29W107
+N29W108
+N29W109
+N29W110
+N29W111
+N29W112
+N29W113
+N29W114
+N29W115
+N29W116
+N29W119
+N30W082
+N30W083
+N30W084
+N30W085
+N30W086
+N30W087
+N30W088
+N30W089
+N30W090
+N30W091
+N30W092
+N30W093
+N30W094
+N30W095
+N30W096
+N30W097
+N30W098
+N30W099
+N30W100
+N30W101
+N30W102
+N30W103
+N30W104
+N30W105
+N30W106
+N30W107
+N30W108
+N30W109
+N30W110
+N30W111
+N30W112
+N30W113
+N30W114
+N30W115
+N30W116
+N30W117
+N31W081
+N31W082
+N31W083
+N31W084
+N31W085
+N31W086
+N31W087
+N31W088
+N31W089
+N31W090
+N31W091
+N31W092
+N31W093
+N31W094
+N31W095
+N31W096
+N31W097
+N31W098
+N31W099
+N31W100
+N31W101
+N31W102
+N31W103
+N31W104
+N31W105
+N31W106
+N31W107
+N31W108
+N31W109
+N31W110
+N31W111
+N31W112
+N31W113
+N31W114
+N31W115
+N31W116
+N31W117
+N32W065
+N32W080
+N32W081
+N32W082
+N32W083
+N32W084
+N32W085
+N32W086
+N32W087
+N32W088
+N32W089
+N32W090
+N32W091
+N32W092
+N32W093
+N32W094
+N32W095
+N32W096
+N32W097
+N32W098
+N32W099
+N32W100
+N32W101
+N32W102
+N32W103
+N32W104
+N32W105
+N32W106
+N32W107
+N32W108
+N32W109
+N32W110
+N32W111
+N32W112
+N32W113
+N32W114
+N32W115
+N32W116
+N32W117
+N32W118
+N32W119
+N33W078
+N33W079
+N33W080
+N33W081
+N33W082
+N33W083
+N33W084
+N33W085
+N33W086
+N33W087
+N33W088
+N33W089
+N33W090
+N33W091
+N33W092
+N33W093
+N33W094
+N33W095
+N33W096
+N33W097
+N33W098
+N33W099
+N33W100
+N33W101
+N33W102
+N33W103
+N33W104
+N33W105
+N33W106
+N33W107
+N33W108
+N33W109
+N33W110
+N33W111
+N33W112
+N33W113
+N33W114
+N33W115
+N33W116
+N33W117
+N33W118
+N33W119
+N33W120
+N33W121
+N34W077
+N34W078
+N34W079
+N34W080
+N34W081
+N34W082
+N34W083
+N34W084
+N34W085
+N34W086
+N34W087
+N34W088
+N34W089
+N34W090
+N34W091
+N34W092
+N34W093
+N34W094
+N34W095
+N34W096
+N34W097
+N34W098
+N34W099
+N34W100
+N34W101
+N34W102
+N34W103
+N34W104
+N34W105
+N34W106
+N34W107
+N34W108
+N34W109
+N34W110
+N34W111
+N34W112
+N34W113
+N34W114
+N34W115
+N34W116
+N34W117
+N34W118
+N34W119
+N34W120
+N34W121
+N35W076
+N35W077
+N35W078
+N35W079
+N35W080
+N35W081
+N35W082
+N35W083
+N35W084
+N35W085
+N35W086
+N35W087
+N35W088
+N35W089
+N35W090
+N35W091
+N35W092
+N35W093
+N35W094
+N35W095
+N35W096
+N35W097
+N35W098
+N35W099
+N35W100
+N35W101
+N35W102
+N35W103
+N35W104
+N35W105
+N35W106
+N35W107
+N35W108
+N35W109
+N35W110
+N35W111
+N35W112
+N35W113
+N35W114
+N35W115
+N35W116
+N35W117
+N35W118
+N35W119
+N35W120
+N35W121
+N35W122
+N36W076
+N36W077
+N36W078
+N36W079
+N36W080
+N36W081
+N36W082
+N36W083
+N36W084
+N36W085
+N36W086
+N36W087
+N36W088
+N36W089
+N36W090
+N36W091
+N36W092
+N36W093
+N36W094
+N36W095
+N36W096
+N36W097
+N36W098
+N36W099
+N36W100
+N36W101
+N36W102
+N36W103
+N36W104
+N36W105
+N36W106
+N36W107
+N36W108
+N36W109
+N36W110
+N36W111
+N36W112
+N36W113
+N36W114
+N36W115
+N36W116
+N36W117
+N36W118
+N36W119
+N36W120
+N36W121
+N36W122
+N36W123
+N37W076
+N37W077
+N37W078
+N37W079
+N37W080
+N37W081
+N37W082
+N37W083
+N37W084
+N37W085
+N37W086
+N37W087
+N37W088
+N37W089
+N37W090
+N37W091
+N37W092
+N37W093
+N37W094
+N37W095
+N37W096
+N37W097
+N37W098
+N37W099
+N37W100
+N37W101
+N37W102
+N37W103
+N37W104
+N37W105
+N37W106
+N37W107
+N37W108
+N37W109
+N37W110
+N37W111
+N37W112
+N37W113
+N37W114
+N37W115
+N37W116
+N37W117
+N37W118
+N37W119
+N37W120
+N37W121
+N37W122
+N37W123
+N37W124
+N38W075
+N38W076
+N38W077
+N38W078
+N38W079
+N38W080
+N38W081
+N38W082
+N38W083
+N38W084
+N38W085
+N38W086
+N38W087
+N38W088
+N38W089
+N38W090
+N38W091
+N38W092
+N38W093
+N38W094
+N38W095
+N38W096
+N38W097
+N38W098
+N38W099
+N38W100
+N38W101
+N38W102
+N38W103
+N38W104
+N38W105
+N38W106
+N38W107
+N38W108
+N38W109
+N38W110
+N38W111
+N38W112
+N38W113
+N38W114
+N38W115
+N38W116
+N38W117
+N38W118
+N38W119
+N38W120
+N38W121
+N38W122
+N38W123
+N38W124
+N39W075
+N39W076
+N39W077
+N39W078
+N39W079
+N39W080
+N39W081
+N39W082
+N39W083
+N39W084
+N39W085
+N39W086
+N39W087
+N39W088
+N39W089
+N39W090
+N39W091
+N39W092
+N39W093
+N39W094
+N39W095
+N39W096
+N39W097
+N39W098
+N39W099
+N39W100
+N39W101
+N39W102
+N39W103
+N39W104
+N39W105
+N39W106
+N39W107
+N39W108
+N39W109
+N39W110
+N39W111
+N39W112
+N39W113
+N39W114
+N39W115
+N39W116
+N39W117
+N39W118
+N39W119
+N39W120
+N39W121
+N39W122
+N39W123
+N39W124
+N39W125
+N40W073
+N40W074
+N40W075
+N40W076
+N40W077
+N40W078
+N40W079
+N40W080
+N40W081
+N40W082
+N40W083
+N40W084
+N40W085
+N40W086
+N40W087
+N40W088
+N40W089
+N40W090
+N40W091
+N40W092
+N40W093
+N40W094
+N40W095
+N40W096
+N40W097
+N40W098
+N40W099
+N40W100
+N40W101
+N40W102
+N40W103
+N40W104
+N40W105
+N40W106
+N40W107
+N40W108
+N40W109
+N40W110
+N40W111
+N40W112
+N40W113
+N40W114
+N40W115
+N40W116
+N40W117
+N40W118
+N40W119
+N40W120
+N40W121
+N40W122
+N40W123
+N40W124
+N40W125
+N41W070
+N41W071
+N41W072
+N41W073
+N41W074
+N41W075
+N41W076
+N41W077
+N41W078
+N41W079
+N41W080
+N41W081
+N41W082
+N41W083
+N41W084
+N41W085
+N41W086
+N41W087
+N41W088
+N41W089
+N41W090
+N41W091
+N41W092
+N41W093
+N41W094
+N41W095
+N41W096
+N41W097
+N41W098
+N41W099
+N41W100
+N41W101
+N41W102
+N41W103
+N41W104
+N41W105
+N41W106
+N41W107
+N41W108
+N41W109
+N41W110
+N41W111
+N41W112
+N41W113
+N41W114
+N41W115
+N41W116
+N41W117
+N41W118
+N41W119
+N41W120
+N41W121
+N41W122
+N41W123
+N41W124
+N41W125
+N42W071
+N42W072
+N42W073
+N42W074
+N42W075
+N42W076
+N42W077
+N42W078
+N42W079
+N42W080
+N42W081
+N42W082
+N42W083
+N42W084
+N42W085
+N42W086
+N42W087
+N42W088
+N42W089
+N42W090
+N42W091
+N42W092
+N42W093
+N42W094
+N42W095
+N42W096
+N42W097
+N42W098
+N42W099
+N42W100
+N42W101
+N42W102
+N42W103
+N42W104
+N42W105
+N42W106
+N42W107
+N42W108
+N42W109
+N42W110
+N42W111
+N42W112
+N42W113
+N42W114
+N42W115
+N42W116
+N42W117
+N42W118
+N42W119
+N42W120
+N42W121
+N42W122
+N42W123
+N42W124
+N42W125
+N43W060
+N43W061
+N43W065
+N43W066
+N43W067
+N43W069
+N43W070
+N43W071
+N43W072
+N43W073
+N43W074
+N43W075
+N43W076
+N43W077
+N43W078
+N43W079
+N43W080
+N43W081
+N43W082
+N43W083
+N43W084
+N43W085
+N43W086
+N43W087
+N43W088
+N43W089
+N43W090
+N43W091
+N43W092
+N43W093
+N43W094
+N43W095
+N43W096
+N43W097
+N43W098
+N43W099
+N43W100
+N43W101
+N43W102
+N43W103
+N43W104
+N43W105
+N43W106
+N43W107
+N43W108
+N43W109
+N43W110
+N43W111
+N43W112
+N43W113
+N43W114
+N43W115
+N43W116
+N43W117
+N43W118
+N43W119
+N43W120
+N43W121
+N43W122
+N43W123
+N43W124
+N43W125
+N44W060
+N44W062
+N44W063
+N44W064
+N44W065
+N44W066
+N44W067
+N44W068
+N44W069
+N44W070
+N44W071
+N44W072
+N44W073
+N44W074
+N44W075
+N44W076
+N44W077
+N44W078
+N44W079
+N44W080
+N44W081
+N44W082
+N44W083
+N44W084
+N44W085
+N44W086
+N44W087
+N44W088
+N44W089
+N44W090
+N44W091
+N44W092
+N44W093
+N44W094
+N44W095
+N44W096
+N44W097
+N44W098
+N44W099
+N44W100
+N44W101
+N44W102
+N44W103
+N44W104
+N44W105
+N44W106
+N44W107
+N44W108
+N44W109
+N44W110
+N44W111
+N44W112
+N44W113
+N44W114
+N44W115
+N44W116
+N44W117
+N44W118
+N44W119
+N44W120
+N44W121
+N44W122
+N44W123
+N44W124
+N44W125
+N45W060
+N45W061
+N45W062
+N45W063
+N45W064
+N45W065
+N45W066
+N45W067
+N45W068
+N45W069
+N45W070
+N45W071
+N45W072
+N45W073
+N45W074
+N45W075
+N45W076
+N45W077
+N45W078
+N45W079
+N45W080
+N45W081
+N45W082
+N45W083
+N45W084
+N45W085
+N45W086
+N45W087
+N45W088
+N45W089
+N45W090
+N45W091
+N45W092
+N45W093
+N45W094
+N45W095
+N45W096
+N45W097
+N45W098
+N45W099
+N45W100
+N45W101
+N45W102
+N45W103
+N45W104
+N45W105
+N45W106
+N45W107
+N45W108
+N45W109
+N45W110
+N45W111
+N45W112
+N45W113
+N45W114
+N45W115
+N45W116
+N45W117
+N45W118
+N45W119
+N45W120
+N45W121
+N45W122
+N45W123
+N45W124
+N45W125
+N46W053
+N46W054
+N46W055
+N46W056
+N46W057
+N46W060
+N46W061
+N46W062
+N46W063
+N46W064
+N46W065
+N46W066
+N46W067
+N46W068
+N46W069
+N46W070
+N46W071
+N46W072
+N46W073
+N46W074
+N46W075
+N46W076
+N46W077
+N46W078
+N46W079
+N46W080
+N46W081
+N46W082
+N46W083
+N46W084
+N46W085
+N46W086
+N46W087
+N46W088
+N46W089
+N46W090
+N46W091
+N46W092
+N46W093
+N46W094
+N46W095
+N46W096
+N46W097
+N46W098
+N46W099
+N46W100
+N46W101
+N46W102
+N46W103
+N46W104
+N46W105
+N46W106
+N46W107
+N46W108
+N46W109
+N46W110
+N46W111
+N46W112
+N46W113
+N46W114
+N46W115
+N46W116
+N46W117
+N46W118
+N46W119
+N46W120
+N46W121
+N46W122
+N46W123
+N46W124
+N46W125
+N47W053
+N47W054
+N47W055
+N47W056
+N47W057
+N47W058
+N47W059
+N47W060
+N47W061
+N47W062
+N47W063
+N47W064
+N47W065
+N47W066
+N47W067
+N47W068
+N47W069
+N47W070
+N47W071
+N47W072
+N47W073
+N47W074
+N47W075
+N47W076
+N47W077
+N47W078
+N47W079
+N47W080
+N47W081
+N47W082
+N47W083
+N47W084
+N47W085
+N47W086
+N47W088
+N47W089
+N47W090
+N47W091
+N47W092
+N47W093
+N47W094
+N47W095
+N47W096
+N47W097
+N47W098
+N47W099
+N47W100
+N47W101
+N47W102
+N47W103
+N47W104
+N47W105
+N47W106
+N47W107
+N47W108
+N47W109
+N47W110
+N47W111
+N47W112
+N47W113
+N47W114
+N47W115
+N47W116
+N47W117
+N47W118
+N47W119
+N47W120
+N47W121
+N47W122
+N47W123
+N47W124
+N47W125
+N48W053
+N48W054
+N48W055
+N48W056
+N48W057
+N48W058
+N48W059
+N48W060
+N48W065
+N48W066
+N48W067
+N48W068
+N48W069
+N48W070
+N48W071
+N48W072
+N48W073
+N48W074
+N48W075
+N48W076
+N48W077
+N48W078
+N48W079
+N48W080
+N48W081
+N48W082
+N48W083
+N48W084
+N48W085
+N48W086
+N48W087
+N48W088
+N48W089
+N48W090
+N48W091
+N48W092
+N48W093
+N48W094
+N48W095
+N48W096
+N48W097
+N48W098
+N48W099
+N48W100
+N48W101
+N48W102
+N48W103
+N48W104
+N48W105
+N48W106
+N48W107
+N48W108
+N48W109
+N48W110
+N48W111
+N48W112
+N48W113
+N48W114
+N48W115
+N48W116
+N48W117
+N48W118
+N48W119
+N48W120
+N48W121
+N48W122
+N48W123
+N48W124
+N48W125
+N48W126
+N49W054
+N49W055
+N49W056
+N49W057
+N49W058
+N49W059
+N49W062
+N49W063
+N49W064
+N49W065
+N49W066
+N49W067
+N49W068
+N49W069
+N49W070
+N49W071
+N49W072
+N49W073
+N49W074
+N49W075
+N49W076
+N49W077
+N49W078
+N49W079
+N49W080
+N49W081
+N49W082
+N49W083
+N49W084
+N49W085
+N49W086
+N49W087
+N49W088
+N49W089
+N49W090
+N49W091
+N49W092
+N49W093
+N49W094
+N49W095
+N49W096
+N49W097
+N49W098
+N49W099
+N49W100
+N49W101
+N49W102
+N49W103
+N49W104
+N49W105
+N49W106
+N49W107
+N49W108
+N49W109
+N49W110
+N49W111
+N49W112
+N49W113
+N49W114
+N49W115
+N49W116
+N49W117
+N49W118
+N49W119
+N49W120
+N49W121
+N49W122
+N49W123
+N49W124
+N49W125
+N49W126
+N49W127
+N49W128
+N50W056
+N50W057
+N50W058
+N50W059
+N50W060
+N50W061
+N50W062
+N50W063
+N50W064
+N50W065
+N50W066
+N50W067
+N50W068
+N50W069
+N50W070
+N50W071
+N50W072
+N50W073
+N50W074
+N50W075
+N50W076
+N50W077
+N50W078
+N50W079
+N50W080
+N50W081
+N50W082
+N50W083
+N50W084
+N50W085
+N50W086
+N50W087
+N50W088
+N50W089
+N50W090
+N50W091
+N50W092
+N50W093
+N50W094
+N50W095
+N50W096
+N50W097
+N50W098
+N50W099
+N50W100
+N50W101
+N50W102
+N50W103
+N50W104
+N50W105
+N50W106
+N50W107
+N50W108
+N50W109
+N50W110
+N50W111
+N50W112
+N50W113
+N50W114
+N50W115
+N50W116
+N50W117
+N50W118
+N50W119
+N50W120
+N50W121
+N50W122
+N50W123
+N50W124
+N50W125
+N50W126
+N50W127
+N50W128
+N50W129
+N50W130
+N51E177
+N51E178
+N51E179
+N51W056
+N51W057
+N51W058
+N51W059
+N51W060
+N51W061
+N51W062
+N51W063
+N51W064
+N51W065
+N51W066
+N51W067
+N51W068
+N51W069
+N51W070
+N51W071
+N51W072
+N51W073
+N51W074
+N51W075
+N51W076
+N51W077
+N51W078
+N51W079
+N51W080
+N51W081
+N51W082
+N51W083
+N51W084
+N51W085
+N51W086
+N51W087
+N51W088
+N51W089
+N51W090
+N51W091
+N51W092
+N51W093
+N51W094
+N51W095
+N51W096
+N51W097
+N51W098
+N51W099
+N51W100
+N51W101
+N51W102
+N51W103
+N51W104
+N51W105
+N51W106
+N51W107
+N51W108
+N51W109
+N51W110
+N51W111
+N51W112
+N51W113
+N51W114
+N51W115
+N51W116
+N51W117
+N51W118
+N51W119
+N51W120
+N51W121
+N51W122
+N51W123
+N51W124
+N51W125
+N51W126
+N51W127
+N51W128
+N51W129
+N51W131
+N51W132
+N51W176
+N51W177
+N51W178
+N51W179
+N51W180
+N52E172
+N52E173
+N52E174
+N52E175
+N52E177
+N52E178
+N52E179
+N52W056
+N52W057
+N52W058
+N52W059
+N52W060
+N52W061
+N52W062
+N52W063
+N52W064
+N52W065
+N52W066
+N52W067
+N52W068
+N52W069
+N52W070
+N52W071
+N52W072
+N52W073
+N52W074
+N52W075
+N52W076
+N52W077
+N52W078
+N52W079
+N52W080
+N52W081
+N52W082
+N52W083
+N52W084
+N52W085
+N52W086
+N52W087
+N52W088
+N52W089
+N52W090
+N52W091
+N52W092
+N52W093
+N52W094
+N52W095
+N52W096
+N52W097
+N52W098
+N52W099
+N52W100
+N52W101
+N52W102
+N52W103
+N52W104
+N52W105
+N52W106
+N52W107
+N52W108
+N52W109
+N52W110
+N52W111
+N52W112
+N52W113
+N52W114
+N52W115
+N52W116
+N52W117
+N52W118
+N52W119
+N52W120
+N52W121
+N52W122
+N52W123
+N52W124
+N52W125
+N52W126
+N52W127
+N52W128
+N52W129
+N52W130
+N52W131
+N52W132
+N52W133
+N52W169
+N52W170
+N52W171
+N52W172
+N52W173
+N52W174
+N52W175
+N52W176
+N52W177
+N53E172
+N53W056
+N53W057
+N53W058
+N53W059
+N53W060
+N53W061
+N53W062
+N53W063
+N53W064
+N53W065
+N53W066
+N53W067
+N53W068
+N53W069
+N53W070
+N53W071
+N53W072
+N53W073
+N53W074
+N53W075
+N53W076
+N53W077
+N53W078
+N53W079
+N53W080
+N53W081
+N53W082
+N53W083
+N53W084
+N53W085
+N53W086
+N53W087
+N53W088
+N53W089
+N53W090
+N53W091
+N53W092
+N53W093
+N53W094
+N53W095
+N53W096
+N53W097
+N53W098
+N53W099
+N53W100
+N53W101
+N53W102
+N53W103
+N53W104
+N53W105
+N53W106
+N53W107
+N53W108
+N53W109
+N53W110
+N53W111
+N53W112
+N53W113
+N53W114
+N53W115
+N53W116
+N53W117
+N53W118
+N53W119
+N53W120
+N53W121
+N53W122
+N53W123
+N53W124
+N53W125
+N53W126
+N53W127
+N53W128
+N53W129
+N53W130
+N53W131
+N53W132
+N53W133
+N53W134
+N53W167
+N53W168
+N53W169
+N53W170
+N54W057
+N54W058
+N54W059
+N54W060
+N54W061
+N54W062
+N54W063
+N54W064
+N54W065
+N54W066
+N54W067
+N54W068
+N54W069
+N54W070
+N54W071
+N54W072
+N54W073
+N54W074
+N54W075
+N54W076
+N54W077
+N54W078
+N54W079
+N54W080
+N54W081
+N54W082
+N54W083
+N54W084
+N54W085
+N54W086
+N54W087
+N54W088
+N54W089
+N54W090
+N54W091
+N54W092
+N54W093
+N54W094
+N54W095
+N54W096
+N54W097
+N54W098
+N54W099
+N54W100
+N54W101
+N54W102
+N54W103
+N54W104
+N54W105
+N54W106
+N54W107
+N54W108
+N54W109
+N54W110
+N54W111
+N54W112
+N54W113
+N54W114
+N54W115
+N54W116
+N54W117
+N54W118
+N54W119
+N54W120
+N54W121
+N54W122
+N54W123
+N54W124
+N54W125
+N54W126
+N54W127
+N54W128
+N54W129
+N54W130
+N54W131
+N54W132
+N54W133
+N54W134
+N54W160
+N54W161
+N54W162
+N54W163
+N54W164
+N54W165
+N54W166
+N54W167
+N55W070
+N55W071
+N55W072
+N55W112
+N55W113
+N55W124
+N55W125
+
diff --git a/tim/prune/function/srtm/gen/tiles3.txt b/tim/prune/function/srtm/gen/tiles3.txt
new file mode 100644 (file)
index 0000000..7334788
--- /dev/null
@@ -0,0 +1,1062 @@
+Australia
+S11E119
+S11E120
+S11E121
+S11E122
+S11E123
+S11E124
+S11E132
+S11E133
+S11E141
+S11E142
+S11E143
+S11E147
+S11E148
+S11E149
+S11E150
+S11E151
+S11E152
+S11E153
+S11E161
+S11E162
+S11E165
+S11E166
+S11E179
+S11W140
+S11W151
+S11W161
+S11W162
+S11W166
+S12E122
+S12E130
+S12E131
+S12E132
+S12E133
+S12E134
+S12E135
+S12E136
+S12E141
+S12E142
+S12E143
+S12E144
+S12E151
+S12E152
+S12E153
+S12E154
+S12E159
+S12E160
+S12E166
+S12E169
+S12E170
+S12W152
+S12W166
+S12W172
+S13E122
+S13E123
+S13E130
+S13E131
+S13E132
+S13E133
+S13E134
+S13E135
+S13E136
+S13E141
+S13E142
+S13E143
+S13E168
+S13E176
+S13E177
+S14E125
+S14E126
+S14E127
+S14E129
+S14E130
+S14E131
+S14E132
+S14E133
+S14E134
+S14E135
+S14E136
+S14E141
+S14E142
+S14E143
+S14E144
+S14E166
+S14E167
+S14W164
+S14W172
+S14W173
+S14W177
+S15E121
+S15E123
+S15E124
+S15E125
+S15E126
+S15E127
+S15E128
+S15E129
+S15E130
+S15E131
+S15E132
+S15E133
+S15E134
+S15E135
+S15E136
+S15E141
+S15E142
+S15E143
+S15E144
+S15E145
+S15E166
+S15E167
+S15E168
+S15W139
+S15W142
+S15W145
+S15W146
+S15W147
+S15W148
+S15W149
+S15W169
+S15W170
+S15W171
+S15W172
+S15W178
+S15W179
+S16E123
+S16E124
+S16E125
+S16E126
+S16E127
+S16E128
+S16E129
+S16E130
+S16E131
+S16E132
+S16E133
+S16E134
+S16E135
+S16E136
+S16E137
+S16E141
+S16E142
+S16E143
+S16E144
+S16E145
+S16E166
+S16E167
+S16E168
+S16W141
+S16W143
+S16W145
+S16W146
+S16W147
+S16W148
+S16W149
+S16W155
+S16W174
+S16W176
+S16W180
+S17E122
+S17E123
+S17E124
+S17E125
+S17E126
+S17E127
+S17E128
+S17E129
+S17E130
+S17E131
+S17E132
+S17E133
+S17E134
+S17E135
+S17E136
+S17E137
+S17E138
+S17E139
+S17E140
+S17E141
+S17E142
+S17E143
+S17E144
+S17E145
+S17E146
+S17E149
+S17E150
+S17E167
+S17E168
+S17E177
+S17E178
+S17E179
+S17W141
+S17W142
+S17W143
+S17W144
+S17W145
+S17W146
+S17W147
+S17W150
+S17W151
+S17W152
+S17W153
+S17W154
+S17W155
+S17W180
+S18E118
+S18E119
+S18E122
+S18E123
+S18E124
+S18E125
+S18E126
+S18E127
+S18E128
+S18E129
+S18E130
+S18E131
+S18E132
+S18E133
+S18E134
+S18E135
+S18E136
+S18E137
+S18E138
+S18E139
+S18E140
+S18E141
+S18E142
+S18E143
+S18E144
+S18E145
+S18E146
+S18E148
+S18E155
+S18E168
+S18E176
+S18E177
+S18E178
+S18E179
+S18W139
+S18W141
+S18W142
+S18W143
+S18W144
+S18W145
+S18W146
+S18W149
+S18W150
+S18W151
+S18W179
+S18W180
+S19E121
+S19E122
+S19E123
+S19E124
+S19E125
+S19E126
+S19E127
+S19E128
+S19E129
+S19E130
+S19E131
+S19E132
+S19E133
+S19E134
+S19E135
+S19E136
+S19E137
+S19E138
+S19E139
+S19E140
+S19E141
+S19E142
+S19E143
+S19E144
+S19E145
+S19E146
+S19E162
+S19E163
+S19E168
+S19E169
+S19E177
+S19E178
+S19E179
+S19W137
+S19W138
+S19W139
+S19W140
+S19W141
+S19W142
+S19W143
+S19W160
+S19W164
+S19W170
+S19W174
+S19W175
+S19W179
+S19W180
+S20E118
+S20E119
+S20E120
+S20E121
+S20E122
+S20E123
+S20E124
+S20E125
+S20E126
+S20E127
+S20E128
+S20E129
+S20E130
+S20E131
+S20E132
+S20E133
+S20E134
+S20E135
+S20E136
+S20E137
+S20E138
+S20E139
+S20E140
+S20E141
+S20E142
+S20E143
+S20E144
+S20E145
+S20E146
+S20E147
+S20E148
+S20E158
+S20E163
+S20E169
+S20E170
+S20E177
+S20E178
+S20E179
+S20W139
+S20W140
+S20W141
+S20W142
+S20W145
+S20W146
+S20W158
+S20W159
+S20W170
+S20W175
+S20W176
+S20W179
+S20W180
+S21E115
+S21E116
+S21E117
+S21E118
+S21E119
+S21E120
+S21E121
+S21E122
+S21E123
+S21E124
+S21E125
+S21E126
+S21E127
+S21E128
+S21E129
+S21E130
+S21E131
+S21E132
+S21E133
+S21E134
+S21E135
+S21E136
+S21E137
+S21E138
+S21E139
+S21E140
+S21E141
+S21E142
+S21E143
+S21E144
+S21E145
+S21E146
+S21E147
+S21E148
+S21E149
+S21E150
+S21E154
+S21E163
+S21E164
+S21E165
+S21E166
+S21E167
+S21E169
+S21W139
+S21W140
+S21W144
+S21W158
+S21W159
+S21W175
+S21W176
+S21W179
+S22E113
+S22E114
+S22E115
+S22E116
+S22E117
+S22E118
+S22E119
+S22E120
+S22E121
+S22E122
+S22E123
+S22E124
+S22E125
+S22E126
+S22E127
+S22E128
+S22E129
+S22E130
+S22E131
+S22E132
+S22E133
+S22E134
+S22E135
+S22E136
+S22E137
+S22E138
+S22E139
+S22E140
+S22E141
+S22E142
+S22E143
+S22E144
+S22E145
+S22E146
+S22E147
+S22E148
+S22E149
+S22E150
+S22E151
+S22E152
+S22E153
+S22E154
+S22E155
+S22E158
+S22E164
+S22E165
+S22E166
+S22E167
+S22E168
+S22W136
+S22W137
+S22W139
+S22W140
+S22W141
+S22W155
+S22W158
+S22W160
+S22W175
+S22W176
+S22W179
+S23E113
+S23E114
+S23E115
+S23E116
+S23E117
+S23E118
+S23E119
+S23E120
+S23E121
+S23E122
+S23E123
+S23E124
+S23E125
+S23E126
+S23E127
+S23E128
+S23E129
+S23E130
+S23E131
+S23E132
+S23E133
+S23E134
+S23E135
+S23E136
+S23E137
+S23E138
+S23E139
+S23E140
+S23E141
+S23E142
+S23E143
+S23E144
+S23E145
+S23E146
+S23E147
+S23E148
+S23E149
+S23E150
+S23E152
+S23E155
+S23E165
+S23E166
+S23E167
+S23E168
+S23E171
+S23E172
+S23W135
+S23W137
+S23W139
+S23W152
+S23W153
+S23W177
+S24E113
+S24E114
+S24E115
+S24E116
+S24E117
+S24E118
+S24E119
+S24E120
+S24E121
+S24E122
+S24E123
+S24E124
+S24E125
+S24E126
+S24E127
+S24E128
+S24E129
+S24E130
+S24E131
+S24E132
+S24E133
+S24E134
+S24E135
+S24E136
+S24E137
+S24E138
+S24E139
+S24E140
+S24E141
+S24E142
+S24E143
+S24E144
+S24E145
+S24E146
+S24E147
+S24E148
+S24E149
+S24E150
+S24E151
+S24E152
+S24E155
+S24W131
+S24W135
+S24W136
+S24W138
+S24W148
+S24W150
+S25E113
+S25E114
+S25E115
+S25E116
+S25E117
+S25E118
+S25E119
+S25E120
+S25E121
+S25E122
+S25E123
+S25E124
+S25E125
+S25E126
+S25E127
+S25E128
+S25E129
+S25E130
+S25E131
+S25E132
+S25E133
+S25E134
+S25E135
+S25E136
+S25E137
+S25E138
+S25E139
+S25E140
+S25E141
+S25E142
+S25E143
+S25E144
+S25E145
+S25E146
+S25E147
+S25E148
+S25E149
+S25E150
+S25E151
+S25E152
+S25E153
+S25W125
+S25W129
+S26E112
+S26E113
+S26E114
+S26E115
+S26E116
+S26E117
+S26E118
+S26E119
+S26E120
+S26E121
+S26E122
+S26E123
+S26E124
+S26E125
+S26E126
+S26E127
+S26E128
+S26E129
+S26E130
+S26E131
+S26E132
+S26E133
+S26E134
+S26E135
+S26E136
+S26E137
+S26E138
+S26E139
+S26E140
+S26E141
+S26E142
+S26E143
+S26E144
+S26E145
+S26E146
+S26E147
+S26E148
+S26E149
+S26E150
+S26E151
+S26E152
+S26E153
+S26W131
+S27E113
+S27E114
+S27E115
+S27E116
+S27E117
+S27E118
+S27E119
+S27E120
+S27E121
+S27E122
+S27E123
+S27E124
+S27E125
+S27E126
+S27E127
+S27E128
+S27E129
+S27E130
+S27E131
+S27E132
+S27E133
+S27E134
+S27E135
+S27E136
+S27E137
+S27E138
+S27E139
+S27E140
+S27E141
+S27E142
+S27E143
+S27E144
+S27E145
+S27E146
+S27E147
+S27E148
+S27E149
+S27E150
+S27E151
+S27E152
+S27E153
+S27W106
+S28E113
+S28E114
+S28E115
+S28E116
+S28E117
+S28E118
+S28E119
+S28E120
+S28E121
+S28E122
+S28E123
+S28E124
+S28E125
+S28E126
+S28E127
+S28E128
+S28E129
+S28E130
+S28E131
+S28E132
+S28E133
+S28E134
+S28E135
+S28E136
+S28E137
+S28E138
+S28E139
+S28E140
+S28E141
+S28E142
+S28E143
+S28E144
+S28E145
+S28E146
+S28E147
+S28E148
+S28E149
+S28E150
+S28E151
+S28E152
+S28E153
+S28W110
+S28W144
+S28W145
+S29E113
+S29E114
+S29E115
+S29E116
+S29E117
+S29E118
+S29E119
+S29E120
+S29E121
+S29E122
+S29E123
+S29E124
+S29E125
+S29E126
+S29E127
+S29E128
+S29E129
+S29E130
+S29E131
+S29E132
+S29E133
+S29E134
+S29E135
+S29E136
+S29E137
+S29E138
+S29E139
+S29E140
+S29E141
+S29E142
+S29E143
+S29E144
+S29E145
+S29E146
+S29E147
+S29E148
+S29E149
+S29E150
+S29E151
+S29E152
+S29E153
+S30E114
+S30E115
+S30E116
+S30E117
+S30E118
+S30E119
+S30E120
+S30E121
+S30E122
+S30E123
+S30E124
+S30E125
+S30E126
+S30E127
+S30E128
+S30E129
+S30E130
+S30E131
+S30E132
+S30E133
+S30E134
+S30E135
+S30E136
+S30E137
+S30E138
+S30E139
+S30E140
+S30E141
+S30E142
+S30E143
+S30E144
+S30E145
+S30E146
+S30E147
+S30E148
+S30E149
+S30E150
+S30E151
+S30E152
+S30E153
+S31E114
+S31E115
+S31E116
+S31E117
+S31E118
+S31E119
+S31E120
+S31E121
+S31E122
+S31E123
+S31E124
+S31E125
+S31E126
+S31E127
+S31E128
+S31E129
+S31E130
+S31E131
+S31E132
+S31E133
+S31E134
+S31E135
+S31E136
+S31E137
+S31E138
+S31E139
+S31E140
+S31E141
+S31E142
+S31E143
+S31E144
+S31E145
+S31E146
+S31E147
+S31E148
+S31E149
+S31E150
+S31E151
+S31E152
+S31E153
+S32E115
+S32E116
+S32E117
+S32E118
+S32E119
+S32E120
+S32E121
+S32E122
+S32E123
+S32E124
+S32E125
+S32E126
+S32E127
+S32E128
+S32E129
+S32E130
+S32E131
+S32E132
+S32E133
+S32E134
+S32E135
+S32E136
+S32E137
+S32E138
+S32E139
+S32E140
+S32E141
+S32E142
+S32E143
+S32E144
+S32E145
+S32E146
+S32E147
+S32E148
+S32E149
+S32E150
+S32E151
+S32E152
+S32E153
+S32E159
+S33E115
+S33E116
+S33E117
+S33E118
+S33E119
+S33E120
+S33E121
+S33E122
+S33E123
+S33E124
+S33E125
+S33E126
+S33E127
+S33E128
+S33E132
+S33E133
+S33E134
+S33E135
+S33E136
+S33E137
+S33E138
+S33E139
+S33E140
+S33E141
+S33E142
+S33E143
+S33E144
+S33E145
+S33E146
+S33E147
+S33E148
+S33E149
+S33E150
+S33E151
+S33E152
+S34E114
+S34E115
+S34E116
+S34E117
+S34E118
+S34E119
+S34E120
+S34E121
+S34E122
+S34E123
+S34E124
+S34E134
+S34E135
+S34E136
+S34E137
+S34E138
+S34E139
+S34E140
+S34E141
+S34E142
+S34E143
+S34E144
+S34E145
+S34E146
+S34E147
+S34E148
+S34E149
+S34E150
+S34E151
+S35E114
+S35E115
+S35E116
+S35E117
+S35E118
+S35E119
+S35E120
+S35E121
+S35E122
+S35E123
+S35E134
+S35E135
+S35E136
+S35E137
+S35E138
+S35E139
+S35E140
+S35E141
+S35E142
+S35E143
+S35E144
+S35E145
+S35E146
+S35E147
+S35E148
+S35E149
+S35E150
+S35E151
+S36E116
+S36E117
+S36E118
+S36E135
+S36E136
+S36E137
+S36E138
+S36E139
+S36E140
+S36E141
+S36E142
+S36E143
+S36E144
+S36E145
+S36E146
+S36E147
+S36E148
+S36E149
+S36E150
+S37E136
+S37E137
+S37E139
+S37E140
+S37E141
+S37E142
+S37E143
+S37E144
+S37E145
+S37E146
+S37E147
+S37E148
+S37E149
+S37E150
+S38E139
+S38E140
+S38E141
+S38E142
+S38E143
+S38E144
+S38E145
+S38E146
+S38E147
+S38E148
+S38E149
+S38E150
+S39E140
+S39E141
+S39E142
+S39E143
+S39E144
+S39E145
+S39E146
+S39E147
+S40E143
+S40E144
+S40E146
+S40E147
+S40E148
+S41E143
+S41E144
+S41E145
+S41E146
+S41E147
+S41E148
+S42E144
+S42E145
+S42E146
+S42E147
+S42E148
+S43E145
+S43E146
+S43E147
+S43E148
+S44E145
+S44E146
+S44E147
+S44E148
+
diff --git a/tim/prune/function/srtm/gen/tiles4.txt b/tim/prune/function/srtm/gen/tiles4.txt
new file mode 100644 (file)
index 0000000..3894bcd
--- /dev/null
@@ -0,0 +1,143 @@
+Islands
+N16W170
+N18W156
+N19W155
+N19W156
+N19W157
+N20W156
+N20W157
+N20W158
+N21W157
+N21W158
+N21W159
+N21W160
+N21W161
+N22W160
+N22W161
+N23W162
+N23W165
+N23W167
+N24W168
+N25W168
+N25W172
+N26W174
+N27W176
+N28W178
+N28W179
+S08W015
+S16W006
+S17W006
+S21W029
+S21W030
+S29E167
+S30E167
+S30W178
+S31W179
+S32W179
+S35E172
+S35E173
+S36E173
+S36E174
+S36E175
+S37E173
+S37E174
+S37E175
+S37E176
+S38E077
+S38E174
+S38E175
+S38E176
+S38E177
+S38E178
+S38W013
+S39E077
+S39E174
+S39E175
+S39E176
+S39E177
+S39E178
+S40E173
+S40E174
+S40E175
+S40E176
+S40E177
+S40E178
+S41E172
+S41E173
+S41E174
+S41E175
+S41E176
+S41W010
+S41W011
+S42E171
+S42E172
+S42E173
+S42E174
+S42E175
+S42E176
+S43E170
+S43E171
+S43E172
+S43E173
+S43E174
+S44E168
+S44E169
+S44E170
+S44E171
+S44E172
+S44E173
+S44W176
+S44W177
+S45E167
+S45E168
+S45E169
+S45E170
+S45E171
+S45W176
+S45W177
+S46E050
+S46E166
+S46E167
+S46E168
+S46E169
+S46E170
+S46E171
+S47E037
+S47E038
+S47E050
+S47E051
+S47E052
+S47E166
+S47E167
+S47E168
+S47E169
+S47E170
+S48E167
+S48E168
+S48E179
+S49E068
+S49E069
+S49E166
+S50E068
+S50E069
+S50E070
+S50E178
+S51E068
+S51E165
+S51E166
+S53E073
+S53E168
+S53E169
+S54E072
+S54E073
+S54W038
+S54W039
+S55E003
+S55E158
+S55W036
+S55W037
+S55W038
+S55W039
+S56E158
+S56W035
+
diff --git a/tim/prune/function/srtm/gen/tiles5.txt b/tim/prune/function/srtm/gen/tiles5.txt
new file mode 100644 (file)
index 0000000..6e4deb7
--- /dev/null
@@ -0,0 +1,1809 @@
+South_America
+N00W050
+N00W051
+N00W052
+N00W053
+N00W054
+N00W055
+N00W056
+N00W057
+N00W058
+N00W059
+N00W060
+N00W061
+N00W062
+N00W063
+N00W064
+N00W065
+N00W066
+N00W067
+N00W068
+N00W069
+N00W070
+N00W071
+N00W072
+N00W073
+N00W074
+N00W075
+N00W076
+N00W077
+N00W078
+N00W079
+N00W080
+N00W081
+N00W090
+N00W091
+N00W092
+N01W050
+N01W051
+N01W052
+N01W053
+N01W054
+N01W055
+N01W056
+N01W057
+N01W058
+N01W059
+N01W060
+N01W061
+N01W062
+N01W063
+N01W064
+N01W065
+N01W066
+N01W067
+N01W068
+N01W069
+N01W070
+N01W071
+N01W072
+N01W073
+N01W074
+N01W075
+N01W076
+N01W077
+N01W078
+N01W079
+N01W080
+N01W092
+N02W051
+N02W052
+N02W053
+N02W054
+N02W055
+N02W056
+N02W057
+N02W058
+N02W059
+N02W060
+N02W061
+N02W062
+N02W063
+N02W064
+N02W065
+N02W066
+N02W067
+N02W068
+N02W069
+N02W070
+N02W071
+N02W072
+N02W073
+N02W074
+N02W075
+N02W076
+N02W077
+N02W078
+N02W079
+N03W051
+N03W052
+N03W053
+N03W054
+N03W055
+N03W056
+N03W057
+N03W058
+N03W059
+N03W060
+N03W061
+N03W062
+N03W063
+N03W064
+N03W065
+N03W066
+N03W067
+N03W068
+N03W069
+N03W070
+N03W071
+N03W072
+N03W073
+N03W074
+N03W075
+N03W076
+N03W077
+N03W078
+N03W079
+N03W082
+N04W052
+N04W053
+N04W054
+N04W055
+N04W056
+N04W057
+N04W058
+N04W059
+N04W060
+N04W061
+N04W062
+N04W063
+N04W064
+N04W065
+N04W066
+N04W067
+N04W068
+N04W069
+N04W070
+N04W071
+N04W072
+N04W073
+N04W074
+N04W075
+N04W076
+N04W077
+N04W078
+N04W082
+N05W053
+N05W054
+N05W055
+N05W056
+N05W057
+N05W058
+N05W059
+N05W060
+N05W061
+N05W062
+N05W063
+N05W064
+N05W065
+N05W066
+N05W067
+N05W068
+N05W069
+N05W070
+N05W071
+N05W072
+N05W073
+N05W074
+N05W075
+N05W076
+N05W077
+N05W078
+N05W088
+N06W056
+N06W057
+N06W058
+N06W059
+N06W060
+N06W061
+N06W062
+N06W063
+N06W064
+N06W065
+N06W066
+N06W067
+N06W068
+N06W069
+N06W070
+N06W071
+N06W072
+N06W073
+N06W074
+N06W075
+N06W076
+N06W077
+N06W078
+N07W059
+N07W060
+N07W061
+N07W062
+N07W063
+N07W064
+N07W065
+N07W066
+N07W067
+N07W068
+N07W069
+N07W070
+N07W071
+N07W072
+N07W073
+N07W074
+N07W075
+N07W076
+N07W077
+N07W078
+N07W079
+N07W080
+N07W081
+N07W082
+N07W083
+N08W060
+N08W061
+N08W062
+N08W063
+N08W064
+N08W065
+N08W066
+N08W067
+N08W068
+N08W069
+N08W070
+N08W071
+N08W072
+N08W073
+N08W074
+N08W075
+N08W076
+N08W077
+N08W078
+N08W079
+N08W080
+N08W081
+N08W082
+N08W083
+N08W084
+N09W061
+N09W062
+N09W063
+N09W064
+N09W065
+N09W066
+N09W067
+N09W068
+N09W069
+N09W070
+N09W071
+N09W072
+N09W073
+N09W074
+N09W075
+N09W076
+N09W077
+N09W078
+N09W079
+N09W080
+N09W081
+N09W082
+N09W083
+N09W084
+N09W085
+N09W086
+N10W061
+N10W062
+N10W063
+N10W064
+N10W065
+N10W066
+N10W067
+N10W068
+N10W069
+N10W070
+N10W071
+N10W072
+N10W073
+N10W074
+N10W075
+N10W076
+N10W084
+N10W085
+N10W086
+N11W061
+N11W062
+N11W064
+N11W065
+N11W067
+N11W068
+N11W069
+N11W070
+N11W071
+N11W072
+N11W073
+N11W074
+N11W075
+N11W084
+N11W085
+N11W086
+N11W087
+N12W062
+N12W069
+N12W070
+N12W071
+N12W072
+N12W073
+N12W082
+N12W083
+N12W084
+N12W085
+N12W086
+N12W087
+N12W088
+N13W060
+N13W061
+N13W062
+N13W081
+N13W082
+N13W084
+N13W085
+N13W086
+N13W087
+N13W088
+N13W089
+N13W090
+N13W091
+N13W092
+N14W061
+N14W062
+N14W081
+N14W083
+N14W084
+N14W085
+N14W086
+N14W087
+N14W088
+N14W089
+N14W090
+N14W091
+N14W092
+N14W093
+S01W047
+S01W048
+S01W049
+S01W050
+S01W051
+S01W052
+S01W053
+S01W054
+S01W055
+S01W056
+S01W057
+S01W058
+S01W059
+S01W060
+S01W061
+S01W062
+S01W063
+S01W064
+S01W065
+S01W066
+S01W067
+S01W068
+S01W069
+S01W070
+S01W071
+S01W072
+S01W073
+S01W074
+S01W075
+S01W076
+S01W077
+S01W078
+S01W079
+S01W080
+S01W081
+S01W090
+S01W091
+S01W092
+S02W045
+S02W046
+S02W047
+S02W048
+S02W049
+S02W050
+S02W051
+S02W052
+S02W053
+S02W054
+S02W055
+S02W056
+S02W057
+S02W058
+S02W059
+S02W060
+S02W061
+S02W062
+S02W063
+S02W064
+S02W065
+S02W066
+S02W067
+S02W068
+S02W069
+S02W070
+S02W071
+S02W072
+S02W073
+S02W074
+S02W075
+S02W076
+S02W077
+S02W078
+S02W079
+S02W080
+S02W081
+S02W082
+S02W090
+S02W091
+S02W092
+S03W040
+S03W041
+S03W042
+S03W043
+S03W044
+S03W045
+S03W046
+S03W047
+S03W048
+S03W049
+S03W050
+S03W051
+S03W052
+S03W053
+S03W054
+S03W055
+S03W056
+S03W057
+S03W058
+S03W059
+S03W060
+S03W061
+S03W062
+S03W063
+S03W064
+S03W065
+S03W066
+S03W067
+S03W068
+S03W069
+S03W070
+S03W071
+S03W072
+S03W073
+S03W074
+S03W075
+S03W076
+S03W077
+S03W078
+S03W079
+S03W080
+S03W081
+S03W082
+S04W033
+S04W034
+S04W039
+S04W040
+S04W041
+S04W042
+S04W043
+S04W044
+S04W045
+S04W046
+S04W047
+S04W048
+S04W049
+S04W050
+S04W051
+S04W052
+S04W053
+S04W054
+S04W055
+S04W056
+S04W057
+S04W058
+S04W059
+S04W060
+S04W061
+S04W062
+S04W063
+S04W064
+S04W065
+S04W066
+S04W067
+S04W068
+S04W069
+S04W070
+S04W071
+S04W072
+S04W073
+S04W074
+S04W075
+S04W076
+S04W077
+S04W078
+S04W079
+S04W080
+S04W081
+S05W037
+S05W038
+S05W039
+S05W040
+S05W041
+S05W042
+S05W043
+S05W044
+S05W045
+S05W046
+S05W047
+S05W048
+S05W049
+S05W050
+S05W051
+S05W052
+S05W053
+S05W054
+S05W055
+S05W056
+S05W057
+S05W058
+S05W059
+S05W060
+S05W061
+S05W062
+S05W063
+S05W064
+S05W065
+S05W066
+S05W067
+S05W068
+S05W069
+S05W070
+S05W071
+S05W072
+S05W073
+S05W074
+S05W075
+S05W076
+S05W077
+S05W078
+S05W079
+S05W080
+S05W081
+S05W082
+S06W036
+S06W037
+S06W038
+S06W039
+S06W040
+S06W041
+S06W042
+S06W043
+S06W044
+S06W045
+S06W046
+S06W047
+S06W048
+S06W049
+S06W050
+S06W051
+S06W052
+S06W053
+S06W054
+S06W055
+S06W056
+S06W057
+S06W058
+S06W059
+S06W060
+S06W061
+S06W062
+S06W063
+S06W064
+S06W065
+S06W066
+S06W067
+S06W068
+S06W069
+S06W070
+S06W071
+S06W072
+S06W073
+S06W074
+S06W075
+S06W076
+S06W077
+S06W078
+S06W079
+S06W080
+S06W081
+S06W082
+S07W035
+S07W036
+S07W037
+S07W038
+S07W039
+S07W040
+S07W041
+S07W042
+S07W043
+S07W044
+S07W045
+S07W046
+S07W047
+S07W048
+S07W049
+S07W050
+S07W051
+S07W052
+S07W053
+S07W054
+S07W055
+S07W056
+S07W057
+S07W058
+S07W059
+S07W060
+S07W061
+S07W062
+S07W063
+S07W064
+S07W065
+S07W066
+S07W067
+S07W068
+S07W069
+S07W070
+S07W071
+S07W072
+S07W073
+S07W074
+S07W075
+S07W076
+S07W077
+S07W078
+S07W079
+S07W080
+S07W081
+S07W082
+S08W035
+S08W036
+S08W037
+S08W038
+S08W039
+S08W040
+S08W041
+S08W042
+S08W043
+S08W044
+S08W045
+S08W046
+S08W047
+S08W048
+S08W049
+S08W050
+S08W051
+S08W052
+S08W053
+S08W054
+S08W055
+S08W056
+S08W057
+S08W058
+S08W059
+S08W060
+S08W061
+S08W062
+S08W063
+S08W064
+S08W065
+S08W066
+S08W067
+S08W068
+S08W069
+S08W070
+S08W071
+S08W072
+S08W073
+S08W074
+S08W075
+S08W076
+S08W077
+S08W078
+S08W079
+S08W080
+S09W035
+S09W036
+S09W037
+S09W038
+S09W039
+S09W040
+S09W041
+S09W042
+S09W043
+S09W044
+S09W045
+S09W046
+S09W047
+S09W048
+S09W049
+S09W050
+S09W051
+S09W052
+S09W053
+S09W054
+S09W055
+S09W056
+S09W057
+S09W058
+S09W059
+S09W060
+S09W061
+S09W062
+S09W063
+S09W064
+S09W065
+S09W066
+S09W067
+S09W068
+S09W069
+S09W070
+S09W071
+S09W072
+S09W073
+S09W074
+S09W075
+S09W076
+S09W077
+S09W078
+S09W079
+S09W080
+S10W036
+S10W037
+S10W038
+S10W039
+S10W040
+S10W041
+S10W042
+S10W043
+S10W044
+S10W045
+S10W046
+S10W047
+S10W048
+S10W049
+S10W050
+S10W051
+S10W052
+S10W053
+S10W054
+S10W055
+S10W056
+S10W057
+S10W058
+S10W059
+S10W060
+S10W061
+S10W062
+S10W063
+S10W064
+S10W065
+S10W066
+S10W067
+S10W068
+S10W069
+S10W070
+S10W071
+S10W072
+S10W073
+S10W074
+S10W075
+S10W076
+S10W077
+S10W078
+S10W079
+S11W037
+S11W038
+S11W039
+S11W040
+S11W041
+S11W042
+S11W043
+S11W044
+S11W045
+S11W046
+S11W047
+S11W048
+S11W049
+S11W050
+S11W051
+S11W052
+S11W053
+S11W054
+S11W055
+S11W056
+S11W057
+S11W058
+S11W059
+S11W060
+S11W061
+S11W062
+S11W063
+S11W064
+S11W065
+S11W066
+S11W067
+S11W068
+S11W069
+S11W070
+S11W071
+S11W072
+S11W073
+S11W074
+S11W075
+S11W076
+S11W077
+S11W078
+S11W079
+S12W038
+S12W039
+S12W040
+S12W041
+S12W042
+S12W043
+S12W044
+S12W045
+S12W046
+S12W047
+S12W048
+S12W049
+S12W050
+S12W051
+S12W052
+S12W053
+S12W054
+S12W055
+S12W056
+S12W057
+S12W058
+S12W059
+S12W060
+S12W061
+S12W062
+S12W063
+S12W064
+S12W065
+S12W066
+S12W067
+S12W068
+S12W069
+S12W070
+S12W071
+S12W072
+S12W073
+S12W074
+S12W075
+S12W076
+S12W077
+S12W078
+S13W038
+S13W039
+S13W040
+S13W041
+S13W042
+S13W043
+S13W044
+S13W045
+S13W046
+S13W047
+S13W048
+S13W049
+S13W050
+S13W051
+S13W052
+S13W053
+S13W054
+S13W055
+S13W056
+S13W057
+S13W058
+S13W059
+S13W060
+S13W061
+S13W062
+S13W063
+S13W064
+S13W065
+S13W066
+S13W067
+S13W068
+S13W069
+S13W070
+S13W071
+S13W072
+S13W073
+S13W074
+S13W075
+S13W076
+S13W077
+S13W078
+S14W039
+S14W040
+S14W041
+S14W042
+S14W043
+S14W044
+S14W045
+S14W046
+S14W047
+S14W048
+S14W049
+S14W050
+S14W051
+S14W052
+S14W053
+S14W054
+S14W055
+S14W056
+S14W057
+S14W058
+S14W059
+S14W060
+S14W061
+S14W062
+S14W063
+S14W064
+S14W065
+S14W066
+S14W067
+S14W068
+S14W069
+S14W070
+S14W071
+S14W072
+S14W073
+S14W074
+S14W075
+S14W076
+S14W077
+S15W039
+S15W040
+S15W041
+S15W042
+S15W043
+S15W044
+S15W045
+S15W046
+S15W047
+S15W048
+S15W049
+S15W050
+S15W051
+S15W052
+S15W053
+S15W054
+S15W055
+S15W056
+S15W057
+S15W058
+S15W059
+S15W060
+S15W061
+S15W062
+S15W063
+S15W064
+S15W065
+S15W066
+S15W067
+S15W068
+S15W069
+S15W070
+S15W071
+S15W072
+S15W073
+S15W074
+S15W075
+S15W076
+S15W077
+S16W039
+S16W040
+S16W041
+S16W042
+S16W043
+S16W044
+S16W045
+S16W046
+S16W047
+S16W048
+S16W049
+S16W050
+S16W051
+S16W052
+S16W053
+S16W054
+S16W055
+S16W056
+S16W057
+S16W058
+S16W059
+S16W060
+S16W061
+S16W062
+S16W063
+S16W064
+S16W065
+S16W066
+S16W067
+S16W068
+S16W069
+S16W070
+S16W071
+S16W072
+S16W073
+S16W074
+S16W075
+S16W076
+S17W039
+S17W040
+S17W041
+S17W042
+S17W043
+S17W044
+S17W045
+S17W046
+S17W047
+S17W048
+S17W049
+S17W050
+S17W051
+S17W052
+S17W053
+S17W054
+S17W055
+S17W056
+S17W057
+S17W058
+S17W059
+S17W060
+S17W061
+S17W062
+S17W063
+S17W064
+S17W065
+S17W066
+S17W067
+S17W068
+S17W070
+S17W071
+S17W072
+S17W073
+S17W074
+S17W075
+S18W039
+S18W040
+S18W041
+S18W042
+S18W043
+S18W044
+S18W045
+S18W046
+S18W047
+S18W048
+S18W049
+S18W050
+S18W051
+S18W052
+S18W053
+S18W054
+S18W055
+S18W056
+S18W057
+S18W058
+S18W059
+S18W060
+S18W061
+S18W062
+S18W063
+S18W064
+S18W065
+S18W066
+S18W067
+S18W068
+S18W069
+S18W070
+S18W071
+S18W072
+S18W073
+S19W040
+S19W041
+S19W042
+S19W043
+S19W044
+S19W045
+S19W046
+S19W047
+S19W048
+S19W049
+S19W050
+S19W051
+S19W052
+S19W053
+S19W054
+S19W055
+S19W056
+S19W057
+S19W058
+S19W059
+S19W060
+S19W061
+S19W062
+S19W063
+S19W064
+S19W065
+S19W066
+S19W067
+S19W068
+S19W069
+S19W070
+S19W071
+S20W040
+S20W041
+S20W042
+S20W043
+S20W044
+S20W045
+S20W046
+S20W047
+S20W048
+S20W049
+S20W050
+S20W051
+S20W052
+S20W053
+S20W054
+S20W055
+S20W056
+S20W057
+S20W058
+S20W059
+S20W060
+S20W061
+S20W062
+S20W063
+S20W064
+S20W065
+S20W066
+S20W067
+S20W068
+S20W069
+S20W070
+S20W071
+S21W041
+S21W042
+S21W043
+S21W044
+S21W045
+S21W046
+S21W047
+S21W048
+S21W049
+S21W050
+S21W051
+S21W052
+S21W053
+S21W054
+S21W055
+S21W056
+S21W057
+S21W058
+S21W059
+S21W060
+S21W061
+S21W062
+S21W063
+S21W064
+S21W065
+S21W066
+S21W067
+S21W068
+S21W069
+S21W070
+S21W071
+S22W041
+S22W042
+S22W043
+S22W044
+S22W045
+S22W046
+S22W047
+S22W048
+S22W049
+S22W050
+S22W051
+S22W052
+S22W053
+S22W054
+S22W055
+S22W056
+S22W057
+S22W058
+S22W059
+S22W060
+S22W061
+S22W062
+S22W063
+S22W064
+S22W065
+S22W066
+S22W067
+S22W068
+S22W069
+S22W070
+S22W071
+S23W041
+S23W042
+S23W043
+S23W044
+S23W045
+S23W046
+S23W047
+S23W048
+S23W049
+S23W050
+S23W051
+S23W052
+S23W053
+S23W054
+S23W055
+S23W056
+S23W057
+S23W058
+S23W059
+S23W060
+S23W061
+S23W062
+S23W063
+S23W064
+S23W065
+S23W066
+S23W067
+S23W068
+S23W069
+S23W070
+S23W071
+S24W042
+S24W043
+S24W044
+S24W045
+S24W046
+S24W047
+S24W048
+S24W049
+S24W050
+S24W051
+S24W052
+S24W053
+S24W054
+S24W055
+S24W056
+S24W057
+S24W058
+S24W059
+S24W060
+S24W061
+S24W062
+S24W063
+S24W064
+S24W065
+S24W066
+S24W067
+S24W068
+S24W069
+S24W070
+S24W071
+S25W046
+S25W047
+S25W048
+S25W049
+S25W050
+S25W051
+S25W052
+S25W053
+S25W054
+S25W055
+S25W056
+S25W057
+S25W058
+S25W059
+S25W060
+S25W061
+S25W062
+S25W063
+S25W064
+S25W065
+S25W066
+S25W067
+S25W068
+S25W069
+S25W070
+S25W071
+S26W048
+S26W049
+S26W050
+S26W051
+S26W052
+S26W053
+S26W054
+S26W055
+S26W056
+S26W057
+S26W058
+S26W059
+S26W060
+S26W061
+S26W062
+S26W063
+S26W064
+S26W065
+S26W066
+S26W067
+S26W068
+S26W069
+S26W070
+S26W071
+S27W049
+S27W050
+S27W051
+S27W052
+S27W053
+S27W054
+S27W055
+S27W056
+S27W057
+S27W058
+S27W059
+S27W060
+S27W061
+S27W062
+S27W063
+S27W064
+S27W065
+S27W066
+S27W067
+S27W068
+S27W069
+S27W070
+S27W071
+S27W080
+S27W081
+S28W049
+S28W050
+S28W051
+S28W052
+S28W053
+S28W054
+S28W055
+S28W056
+S28W057
+S28W058
+S28W059
+S28W060
+S28W061
+S28W062
+S28W063
+S28W064
+S28W065
+S28W066
+S28W067
+S28W068
+S28W069
+S28W070
+S28W071
+S28W072
+S29W049
+S29W050
+S29W051
+S29W052
+S29W053
+S29W054
+S29W055
+S29W056
+S29W057
+S29W058
+S29W059
+S29W060
+S29W061
+S29W062
+S29W063
+S29W064
+S29W065
+S29W066
+S29W067
+S29W068
+S29W069
+S29W070
+S29W071
+S29W072
+S30W050
+S30W051
+S30W052
+S30W053
+S30W054
+S30W055
+S30W056
+S30W057
+S30W058
+S30W059
+S30W060
+S30W061
+S30W062
+S30W063
+S30W064
+S30W065
+S30W066
+S30W067
+S30W068
+S30W069
+S30W070
+S30W071
+S30W072
+S31W051
+S31W052
+S31W053
+S31W054
+S31W055
+S31W056
+S31W057
+S31W058
+S31W059
+S31W060
+S31W061
+S31W062
+S31W063
+S31W064
+S31W065
+S31W066
+S31W067
+S31W068
+S31W069
+S31W070
+S31W071
+S31W072
+S32W051
+S32W052
+S32W053
+S32W054
+S32W055
+S32W056
+S32W057
+S32W058
+S32W059
+S32W060
+S32W061
+S32W062
+S32W063
+S32W064
+S32W065
+S32W066
+S32W067
+S32W068
+S32W069
+S32W070
+S32W071
+S32W072
+S33W052
+S33W053
+S33W054
+S33W055
+S33W056
+S33W057
+S33W058
+S33W059
+S33W060
+S33W061
+S33W062
+S33W063
+S33W064
+S33W065
+S33W066
+S33W067
+S33W068
+S33W069
+S33W070
+S33W071
+S33W072
+S34W053
+S34W054
+S34W055
+S34W056
+S34W057
+S34W058
+S34W059
+S34W060
+S34W061
+S34W062
+S34W063
+S34W064
+S34W065
+S34W066
+S34W067
+S34W068
+S34W069
+S34W070
+S34W071
+S34W072
+S34W079
+S34W081
+S35W054
+S35W055
+S35W056
+S35W057
+S35W058
+S35W059
+S35W060
+S35W061
+S35W062
+S35W063
+S35W064
+S35W065
+S35W066
+S35W067
+S35W068
+S35W069
+S35W070
+S35W071
+S35W072
+S35W073
+S36W058
+S36W059
+S36W060
+S36W061
+S36W062
+S36W063
+S36W064
+S36W065
+S36W066
+S36W067
+S36W068
+S36W069
+S36W070
+S36W071
+S36W072
+S36W073
+S37W057
+S37W058
+S37W059
+S37W060
+S37W061
+S37W062
+S37W063
+S37W064
+S37W065
+S37W066
+S37W067
+S37W068
+S37W069
+S37W070
+S37W071
+S37W072
+S37W073
+S37W074
+S38W057
+S38W058
+S38W059
+S38W060
+S38W061
+S38W062
+S38W063
+S38W064
+S38W065
+S38W066
+S38W067
+S38W068
+S38W069
+S38W070
+S38W071
+S38W072
+S38W073
+S38W074
+S39W058
+S39W059
+S39W060
+S39W061
+S39W062
+S39W063
+S39W064
+S39W065
+S39W066
+S39W067
+S39W068
+S39W069
+S39W070
+S39W071
+S39W072
+S39W073
+S39W074
+S40W062
+S40W063
+S40W064
+S40W065
+S40W066
+S40W067
+S40W068
+S40W069
+S40W070
+S40W071
+S40W072
+S40W073
+S40W074
+S41W063
+S41W064
+S41W065
+S41W066
+S41W067
+S41W068
+S41W069
+S41W070
+S41W071
+S41W072
+S41W073
+S41W074
+S42W063
+S42W064
+S42W065
+S42W066
+S42W067
+S42W068
+S42W069
+S42W070
+S42W071
+S42W072
+S42W073
+S42W074
+S42W075
+S43W064
+S43W065
+S43W066
+S43W067
+S43W068
+S43W069
+S43W070
+S43W071
+S43W072
+S43W073
+S43W074
+S43W075
+S44W065
+S44W066
+S44W067
+S44W068
+S44W069
+S44W070
+S44W071
+S44W072
+S44W073
+S44W074
+S44W075
+S45W066
+S45W067
+S45W068
+S45W069
+S45W070
+S45W071
+S45W072
+S45W073
+S45W074
+S45W075
+S45W076
+S46W066
+S46W067
+S46W068
+S46W069
+S46W070
+S46W071
+S46W072
+S46W073
+S46W074
+S46W075
+S46W076
+S47W067
+S47W068
+S47W069
+S47W070
+S47W071
+S47W072
+S47W073
+S47W074
+S47W075
+S47W076
+S48W066
+S48W067
+S48W068
+S48W069
+S48W070
+S48W071
+S48W072
+S48W073
+S48W074
+S48W075
+S48W076
+S49W066
+S49W067
+S49W068
+S49W069
+S49W070
+S49W071
+S49W072
+S49W073
+S49W074
+S49W075
+S49W076
+S50W068
+S50W069
+S50W070
+S50W071
+S50W072
+S50W073
+S50W074
+S50W075
+S50W076
+S51W062
+S51W068
+S51W069
+S51W070
+S51W071
+S51W072
+S51W073
+S51W074
+S51W075
+S51W076
+S52W058
+S52W059
+S52W060
+S52W061
+S52W062
+S52W069
+S52W070
+S52W071
+S52W072
+S52W073
+S52W074
+S52W075
+S52W076
+S53W059
+S53W060
+S53W061
+S53W062
+S53W069
+S53W070
+S53W071
+S53W072
+S53W073
+S53W074
+S53W075
+S53W076
+S54W068
+S54W069
+S54W070
+S54W071
+S54W072
+S54W073
+S54W074
+S54W075
+S55W064
+S55W065
+S55W066
+S55W067
+S55W068
+S55W069
+S55W070
+S55W071
+S55W072
+S55W073
+S55W074
+S56W067
+S56W068
+S56W069
+S56W070
+S56W071
+S56W072
+s17w069
+
diff --git a/tim/prune/function/srtm/gen/tiles6.txt b/tim/prune/function/srtm/gen/tiles6.txt
new file mode 100644 (file)
index 0000000..959de45
--- /dev/null
@@ -0,0 +1,3251 @@
+Africa
+N00E006
+N00E009
+N00E010
+N00E011
+N00E012
+N00E013
+N00E014
+N00E015
+N00E016
+N00E017
+N00E018
+N00E019
+N00E020
+N00E021
+N00E022
+N00E023
+N00E024
+N00E025
+N00E026
+N00E027
+N00E028
+N00E029
+N00E030
+N00E031
+N00E032
+N00E033
+N00E034
+N00E035
+N00E036
+N00E037
+N00E038
+N00E039
+N00E040
+N00E041
+N00E042
+N00E043
+N01E007
+N01E009
+N01E010
+N01E011
+N01E012
+N01E013
+N01E014
+N01E015
+N01E016
+N01E017
+N01E018
+N01E019
+N01E020
+N01E021
+N01E022
+N01E023
+N01E024
+N01E025
+N01E026
+N01E027
+N01E028
+N01E029
+N01E030
+N01E031
+N01E032
+N01E033
+N01E034
+N01E035
+N01E036
+N01E037
+N01E038
+N01E039
+N01E040
+N01E041
+N01E042
+N01E043
+N01E044
+N01E045
+N02E009
+N02E010
+N02E011
+N02E012
+N02E013
+N02E014
+N02E015
+N02E016
+N02E017
+N02E018
+N02E019
+N02E020
+N02E021
+N02E022
+N02E023
+N02E024
+N02E025
+N02E026
+N02E027
+N02E028
+N02E029
+N02E030
+N02E031
+N02E032
+N02E033
+N02E034
+N02E035
+N02E036
+N02E037
+N02E038
+N02E039
+N02E040
+N02E041
+N02E042
+N02E043
+N02E044
+N02E045
+N02E046
+N03E008
+N03E009
+N03E010
+N03E011
+N03E012
+N03E013
+N03E014
+N03E015
+N03E016
+N03E017
+N03E018
+N03E019
+N03E020
+N03E021
+N03E022
+N03E023
+N03E024
+N03E025
+N03E026
+N03E027
+N03E028
+N03E029
+N03E030
+N03E031
+N03E032
+N03E033
+N03E034
+N03E035
+N03E036
+N03E037
+N03E038
+N03E039
+N03E040
+N03E041
+N03E042
+N03E043
+N03E044
+N03E045
+N03E046
+N03E047
+N04E005
+N04E006
+N04E007
+N04E008
+N04E009
+N04E010
+N04E011
+N04E012
+N04E013
+N04E014
+N04E015
+N04E016
+N04E017
+N04E018
+N04E019
+N04E020
+N04E021
+N04E022
+N04E023
+N04E024
+N04E025
+N04E026
+N04E027
+N04E028
+N04E029
+N04E030
+N04E031
+N04E032
+N04E033
+N04E034
+N04E035
+N04E036
+N04E037
+N04E038
+N04E039
+N04E040
+N04E041
+N04E042
+N04E043
+N04E044
+N04E045
+N04E046
+N04E047
+N04E048
+N04W002
+N04W003
+N04W006
+N04W007
+N04W008
+N04W009
+N04W010
+N05E000
+N05E001
+N05E004
+N05E005
+N05E006
+N05E007
+N05E008
+N05E009
+N05E010
+N05E011
+N05E012
+N05E013
+N05E014
+N05E015
+N05E016
+N05E017
+N05E018
+N05E019
+N05E020
+N05E021
+N05E022
+N05E023
+N05E024
+N05E025
+N05E026
+N05E027
+N05E028
+N05E029
+N05E030
+N05E031
+N05E032
+N05E033
+N05E034
+N05E035
+N05E036
+N05E037
+N05E038
+N05E039
+N05E040
+N05E041
+N05E042
+N05E043
+N05E044
+N05E045
+N05E046
+N05E047
+N05E048
+N05W001
+N05W002
+N05W003
+N05W004
+N05W005
+N05W006
+N05W007
+N05W008
+N05W009
+N05W010
+N05W011
+N06E000
+N06E001
+N06E002
+N06E003
+N06E004
+N06E005
+N06E006
+N06E007
+N06E008
+N06E009
+N06E010
+N06E011
+N06E012
+N06E013
+N06E014
+N06E015
+N06E016
+N06E017
+N06E018
+N06E019
+N06E020
+N06E021
+N06E022
+N06E023
+N06E024
+N06E025
+N06E026
+N06E027
+N06E028
+N06E029
+N06E030
+N06E031
+N06E032
+N06E033
+N06E034
+N06E035
+N06E036
+N06E037
+N06E038
+N06E039
+N06E040
+N06E041
+N06E042
+N06E043
+N06E044
+N06E045
+N06E046
+N06E047
+N06E048
+N06E049
+N06W001
+N06W002
+N06W003
+N06W004
+N06W005
+N06W006
+N06W007
+N06W008
+N06W009
+N06W010
+N06W011
+N06W012
+N07E000
+N07E001
+N07E002
+N07E003
+N07E004
+N07E005
+N07E006
+N07E007
+N07E008
+N07E009
+N07E010
+N07E011
+N07E012
+N07E013
+N07E014
+N07E015
+N07E016
+N07E017
+N07E018
+N07E019
+N07E020
+N07E021
+N07E022
+N07E023
+N07E024
+N07E025
+N07E026
+N07E027
+N07E028
+N07E029
+N07E030
+N07E031
+N07E032
+N07E033
+N07E034
+N07E035
+N07E036
+N07E037
+N07E038
+N07E039
+N07E040
+N07E041
+N07E042
+N07E043
+N07E044
+N07E045
+N07E046
+N07E047
+N07E048
+N07E049
+N07W001
+N07W002
+N07W003
+N07W004
+N07W005
+N07W006
+N07W007
+N07W008
+N07W009
+N07W010
+N07W011
+N07W012
+N07W013
+N07W014
+N08E000
+N08E001
+N08E002
+N08E003
+N08E004
+N08E005
+N08E006
+N08E007
+N08E008
+N08E009
+N08E010
+N08E011
+N08E012
+N08E013
+N08E014
+N08E015
+N08E016
+N08E017
+N08E018
+N08E019
+N08E020
+N08E021
+N08E022
+N08E023
+N08E024
+N08E025
+N08E026
+N08E027
+N08E028
+N08E029
+N08E030
+N08E031
+N08E032
+N08E033
+N08E034
+N08E035
+N08E036
+N08E037
+N08E038
+N08E039
+N08E040
+N08E041
+N08E042
+N08E043
+N08E044
+N08E045
+N08E046
+N08E047
+N08E048
+N08E049
+N08E050
+N08W001
+N08W002
+N08W003
+N08W004
+N08W005
+N08W006
+N08W007
+N08W008
+N08W009
+N08W010
+N08W011
+N08W012
+N08W013
+N08W014
+N09E000
+N09E001
+N09E002
+N09E003
+N09E004
+N09E005
+N09E006
+N09E007
+N09E008
+N09E009
+N09E010
+N09E011
+N09E012
+N09E013
+N09E014
+N09E015
+N09E016
+N09E017
+N09E018
+N09E019
+N09E020
+N09E021
+N09E022
+N09E023
+N09E024
+N09E025
+N09E026
+N09E027
+N09E028
+N09E029
+N09E030
+N09E031
+N09E032
+N09E033
+N09E034
+N09E035
+N09E036
+N09E037
+N09E038
+N09E039
+N09E040
+N09E041
+N09E042
+N09E043
+N09E044
+N09E045
+N09E046
+N09E047
+N09E048
+N09E049
+N09E050
+N09W001
+N09W002
+N09W003
+N09W004
+N09W005
+N09W006
+N09W007
+N09W008
+N09W009
+N09W010
+N09W011
+N09W012
+N09W013
+N09W014
+N09W015
+N10E000
+N10E001
+N10E002
+N10E003
+N10E004
+N10E005
+N10E006
+N10E007
+N10E008
+N10E009
+N10E010
+N10E011
+N10E012
+N10E013
+N10E014
+N10E015
+N10E016
+N10E017
+N10E018
+N10E019
+N10E020
+N10E021
+N10E022
+N10E023
+N10E024
+N10E025
+N10E026
+N10E027
+N10E028
+N10E029
+N10E030
+N10E031
+N10E032
+N10E033
+N10E034
+N10E035
+N10E036
+N10E037
+N10E038
+N10E039
+N10E040
+N10E041
+N10E042
+N10E043
+N10E044
+N10E045
+N10E046
+N10E047
+N10E048
+N10E049
+N10E050
+N10E051
+N10W001
+N10W002
+N10W003
+N10W004
+N10W005
+N10W006
+N10W007
+N10W008
+N10W009
+N10W010
+N10W011
+N10W012
+N10W013
+N10W014
+N10W015
+N10W016
+N11E000
+N11E001
+N11E002
+N11E003
+N11E004
+N11E005
+N11E006
+N11E007
+N11E008
+N11E009
+N11E010
+N11E011
+N11E012
+N11E013
+N11E014
+N11E015
+N11E016
+N11E017
+N11E018
+N11E019
+N11E020
+N11E021
+N11E022
+N11E023
+N11E024
+N11E025
+N11E026
+N11E027
+N11E028
+N11E029
+N11E030
+N11E031
+N11E032
+N11E033
+N11E034
+N11E035
+N11E036
+N11E037
+N11E038
+N11E039
+N11E040
+N11E041
+N11E042
+N11E043
+N11E047
+N11E048
+N11E049
+N11E050
+N11E051
+N11W001
+N11W002
+N11W003
+N11W004
+N11W005
+N11W006
+N11W007
+N11W008
+N11W009
+N11W010
+N11W011
+N11W012
+N11W013
+N11W014
+N11W015
+N11W016
+N11W017
+N12E000
+N12E001
+N12E002
+N12E003
+N12E004
+N12E005
+N12E006
+N12E007
+N12E008
+N12E009
+N12E010
+N12E011
+N12E012
+N12E013
+N12E014
+N12E015
+N12E016
+N12E017
+N12E018
+N12E019
+N12E020
+N12E021
+N12E022
+N12E023
+N12E024
+N12E025
+N12E026
+N12E027
+N12E028
+N12E029
+N12E030
+N12E031
+N12E032
+N12E033
+N12E034
+N12E035
+N12E036
+N12E037
+N12E038
+N12E039
+N12E040
+N12E041
+N12E042
+N12E043
+N12E044
+N12E045
+N12E052
+N12E053
+N12E054
+N12W001
+N12W002
+N12W003
+N12W004
+N12W005
+N12W006
+N12W007
+N12W008
+N12W009
+N12W010
+N12W011
+N12W012
+N12W013
+N12W014
+N12W015
+N12W016
+N12W017
+N13E000
+N13E001
+N13E002
+N13E003
+N13E004
+N13E005
+N13E006
+N13E007
+N13E008
+N13E009
+N13E010
+N13E011
+N13E012
+N13E013
+N13E014
+N13E015
+N13E016
+N13E017
+N13E018
+N13E019
+N13E020
+N13E021
+N13E022
+N13E023
+N13E024
+N13E025
+N13E026
+N13E027
+N13E028
+N13E029
+N13E030
+N13E031
+N13E032
+N13E033
+N13E034
+N13E035
+N13E036
+N13E037
+N13E038
+N13E039
+N13E040
+N13E041
+N13E042
+N13E043
+N13E044
+N13E045
+N13E046
+N13E047
+N13E048
+N13W001
+N13W002
+N13W003
+N13W004
+N13W005
+N13W006
+N13W007
+N13W008
+N13W009
+N13W010
+N13W011
+N13W012
+N13W013
+N13W014
+N13W015
+N13W016
+N13W017
+N14E000
+N14E001
+N14E002
+N14E003
+N14E004
+N14E005
+N14E006
+N14E007
+N14E008
+N14E009
+N14E010
+N14E011
+N14E012
+N14E013
+N14E014
+N14E015
+N14E016
+N14E017
+N14E018
+N14E019
+N14E020
+N14E021
+N14E022
+N14E023
+N14E024
+N14E025
+N14E026
+N14E027
+N14E028
+N14E029
+N14E030
+N14E031
+N14E032
+N14E033
+N14E034
+N14E035
+N14E036
+N14E037
+N14E038
+N14E039
+N14E040
+N14E041
+N14E042
+N14E043
+N14E044
+N14E045
+N14E046
+N14E047
+N14E048
+N14E049
+N14E050
+N14W001
+N14W002
+N14W003
+N14W004
+N14W005
+N14W006
+N14W007
+N14W008
+N14W009
+N14W010
+N14W011
+N14W012
+N14W013
+N14W014
+N14W015
+N14W016
+N14W017
+N14W018
+N14W024
+N14W025
+N15E000
+N15E001
+N15E002
+N15E003
+N15E004
+N15E005
+N15E006
+N15E007
+N15E008
+N15E009
+N15E010
+N15E011
+N15E012
+N15E013
+N15E014
+N15E015
+N15E016
+N15E017
+N15E018
+N15E019
+N15E020
+N15E021
+N15E022
+N15E023
+N15E024
+N15E025
+N15E026
+N15E027
+N15E028
+N15E029
+N15E030
+N15E031
+N15E032
+N15E033
+N15E034
+N15E035
+N15E036
+N15E037
+N15E038
+N15E039
+N15E040
+N15E041
+N15E042
+N15E043
+N15E044
+N15E045
+N15E046
+N15E047
+N15E048
+N15E049
+N15E050
+N15E051
+N15E052
+N15W001
+N15W002
+N15W003
+N15W004
+N15W005
+N15W006
+N15W007
+N15W008
+N15W009
+N15W010
+N15W011
+N15W012
+N15W013
+N15W014
+N15W015
+N15W016
+N15W017
+N15W018
+N15W023
+N15W024
+N15W025
+N16E000
+N16E001
+N16E002
+N16E003
+N16E004
+N16E005
+N16E006
+N16E007
+N16E008
+N16E009
+N16E010
+N16E011
+N16E012
+N16E013
+N16E014
+N16E015
+N16E016
+N16E017
+N16E018
+N16E019
+N16E020
+N16E021
+N16E022
+N16E023
+N16E024
+N16E025
+N16E026
+N16E027
+N16E028
+N16E029
+N16E030
+N16E031
+N16E032
+N16E033
+N16E034
+N16E035
+N16E036
+N16E037
+N16E038
+N16E039
+N16E040
+N16E041
+N16E042
+N16E043
+N16E044
+N16E045
+N16E046
+N16E047
+N16E048
+N16E049
+N16E050
+N16E051
+N16E052
+N16E053
+N16E054
+N16E055
+N16W001
+N16W002
+N16W003
+N16W004
+N16W005
+N16W006
+N16W007
+N16W008
+N16W009
+N16W010
+N16W011
+N16W012
+N16W013
+N16W014
+N16W015
+N16W016
+N16W017
+N16W023
+N16W025
+N16W026
+N17E000
+N17E001
+N17E002
+N17E003
+N17E004
+N17E005
+N17E006
+N17E007
+N17E008
+N17E009
+N17E010
+N17E011
+N17E012
+N17E013
+N17E014
+N17E015
+N17E016
+N17E017
+N17E018
+N17E019
+N17E020
+N17E021
+N17E022
+N17E023
+N17E024
+N17E025
+N17E026
+N17E027
+N17E028
+N17E029
+N17E030
+N17E031
+N17E032
+N17E033
+N17E034
+N17E035
+N17E036
+N17E037
+N17E038
+N17E039
+N17E041
+N17E042
+N17E043
+N17E044
+N17E045
+N17E046
+N17E047
+N17E048
+N17E049
+N17E050
+N17E051
+N17E052
+N17E053
+N17E054
+N17E055
+N17E056
+N17W001
+N17W002
+N17W003
+N17W004
+N17W005
+N17W006
+N17W007
+N17W008
+N17W009
+N17W010
+N17W011
+N17W012
+N17W013
+N17W014
+N17W015
+N17W016
+N17W017
+N17W025
+N17W026
+N18E000
+N18E001
+N18E002
+N18E003
+N18E004
+N18E005
+N18E006
+N18E007
+N18E008
+N18E009
+N18E010
+N18E011
+N18E012
+N18E013
+N18E014
+N18E015
+N18E016
+N18E017
+N18E018
+N18E019
+N18E020
+N18E021
+N18E022
+N18E023
+N18E024
+N18E025
+N18E026
+N18E027
+N18E028
+N18E029
+N18E030
+N18E031
+N18E032
+N18E033
+N18E034
+N18E035
+N18E036
+N18E037
+N18E038
+N18E040
+N18E041
+N18E042
+N18E043
+N18E044
+N18E045
+N18E046
+N18E047
+N18E048
+N18E049
+N18E050
+N18E051
+N18E052
+N18E053
+N18E054
+N18E055
+N18E056
+N18E057
+N18W001
+N18W002
+N18W003
+N18W004
+N18W005
+N18W006
+N18W007
+N18W008
+N18W009
+N18W010
+N18W011
+N18W012
+N18W013
+N18W014
+N18W015
+N18W016
+N18W017
+N19E000
+N19E001
+N19E002
+N19E003
+N19E004
+N19E005
+N19E006
+N19E007
+N19E008
+N19E009
+N19E010
+N19E011
+N19E012
+N19E013
+N19E014
+N19E015
+N19E016
+N19E017
+N19E018
+N19E019
+N19E020
+N19E021
+N19E022
+N19E023
+N19E024
+N19E025
+N19E026
+N19E027
+N19E028
+N19E029
+N19E030
+N19E031
+N19E032
+N19E033
+N19E034
+N19E035
+N19E036
+N19E037
+N19E038
+N19E039
+N19E040
+N19E041
+N19E042
+N19E043
+N19E044
+N19E045
+N19E046
+N19E047
+N19E048
+N19E049
+N19E050
+N19E051
+N19E052
+N19E053
+N19E054
+N19E055
+N19E056
+N19E057
+N19W001
+N19W002
+N19W003
+N19W004
+N19W005
+N19W006
+N19W007
+N19W008
+N19W009
+N19W010
+N19W011
+N19W012
+N19W013
+N19W014
+N19W015
+N19W016
+N19W017
+N20E000
+N20E001
+N20E002
+N20E003
+N20E004
+N20E005
+N20E006
+N20E007
+N20E008
+N20E009
+N20E010
+N20E011
+N20E012
+N20E013
+N20E014
+N20E015
+N20E016
+N20E017
+N20E018
+N20E019
+N20E020
+N20E021
+N20E022
+N20E023
+N20E024
+N20E025
+N20E026
+N20E027
+N20E028
+N20E029
+N20E030
+N20E031
+N20E032
+N20E033
+N20E034
+N20E035
+N20E036
+N20E037
+N20E039
+N20E040
+N20E041
+N20E042
+N20E043
+N20E044
+N20E045
+N20E046
+N20E047
+N20E048
+N20E049
+N20E050
+N20E051
+N20E052
+N20E053
+N20E054
+N20E055
+N20E056
+N20E057
+N20E058
+N20W001
+N20W002
+N20W003
+N20W004
+N20W005
+N20W006
+N20W007
+N20W008
+N20W009
+N20W010
+N20W011
+N20W012
+N20W013
+N20W014
+N20W015
+N20W016
+N20W017
+N20W018
+N21E000
+N21E001
+N21E002
+N21E003
+N21E004
+N21E005
+N21E006
+N21E007
+N21E008
+N21E009
+N21E010
+N21E011
+N21E012
+N21E013
+N21E014
+N21E015
+N21E016
+N21E017
+N21E018
+N21E019
+N21E020
+N21E021
+N21E022
+N21E023
+N21E024
+N21E025
+N21E026
+N21E027
+N21E028
+N21E029
+N21E030
+N21E031
+N21E032
+N21E033
+N21E034
+N21E035
+N21E036
+N21E037
+N21E038
+N21E039
+N21E040
+N21E041
+N21E042
+N21E043
+N21E044
+N21E045
+N21E046
+N21E047
+N21E048
+N21E049
+N21E050
+N21E051
+N21E052
+N21E053
+N21E054
+N21E055
+N21E056
+N21E057
+N21E058
+N21E059
+N21W001
+N21W002
+N21W003
+N21W004
+N21W005
+N21W006
+N21W007
+N21W008
+N21W009
+N21W010
+N21W011
+N21W012
+N21W013
+N21W014
+N21W015
+N21W016
+N21W017
+N21W018
+N22E000
+N22E001
+N22E002
+N22E003
+N22E004
+N22E005
+N22E006
+N22E007
+N22E008
+N22E009
+N22E010
+N22E011
+N22E012
+N22E013
+N22E014
+N22E015
+N22E016
+N22E017
+N22E018
+N22E019
+N22E020
+N22E021
+N22E022
+N22E023
+N22E024
+N22E025
+N22E026
+N22E027
+N22E028
+N22E029
+N22E030
+N22E031
+N22E032
+N22E033
+N22E034
+N22E035
+N22E036
+N22E038
+N22E039
+N22E040
+N22E041
+N22E042
+N22E043
+N22E044
+N22E045
+N22E046
+N22E047
+N22E048
+N22E049
+N22E050
+N22E051
+N22E052
+N22E053
+N22E054
+N22E055
+N22E056
+N22E057
+N22E058
+N22E059
+N22W001
+N22W002
+N22W003
+N22W004
+N22W005
+N22W006
+N22W007
+N22W008
+N22W009
+N22W010
+N22W011
+N22W012
+N22W013
+N22W014
+N22W015
+N22W016
+N22W017
+N23E000
+N23E001
+N23E002
+N23E003
+N23E004
+N23E005
+N23E006
+N23E007
+N23E008
+N23E009
+N23E010
+N23E011
+N23E012
+N23E013
+N23E014
+N23E015
+N23E016
+N23E017
+N23E018
+N23E019
+N23E020
+N23E021
+N23E022
+N23E023
+N23E024
+N23E025
+N23E026
+N23E027
+N23E028
+N23E029
+N23E030
+N23E031
+N23E032
+N23E033
+N23E034
+N23E035
+N23E036
+N23E038
+N23E039
+N23E040
+N23E041
+N23E042
+N23E043
+N23E044
+N23E045
+N23E046
+N23E047
+N23E048
+N23E049
+N23E050
+N23E051
+N23E052
+N23E053
+N23E054
+N23E055
+N23E056
+N23E057
+N23E058
+N23E059
+N23W001
+N23W002
+N23W003
+N23W004
+N23W005
+N23W006
+N23W007
+N23W008
+N23W009
+N23W010
+N23W011
+N23W012
+N23W013
+N23W014
+N23W015
+N23W016
+N23W017
+N24E000
+N24E001
+N24E002
+N24E003
+N24E004
+N24E005
+N24E006
+N24E007
+N24E008
+N24E009
+N24E010
+N24E011
+N24E013
+N24E014
+N24E015
+N24E016
+N24E017
+N24E018
+N24E019
+N24E020
+N24E021
+N24E022
+N24E023
+N24E024
+N24E025
+N24E026
+N24E027
+N24E028
+N24E029
+N24E030
+N24E031
+N24E032
+N24E033
+N24E034
+N24E035
+N24E037
+N24E038
+N24E039
+N24E040
+N24E041
+N24E042
+N24E043
+N24E044
+N24E045
+N24E046
+N24E047
+N24E048
+N24E049
+N24E050
+N24E051
+N24E052
+N24E053
+N24E054
+N24E055
+N24E056
+N24E057
+N24W001
+N24W002
+N24W003
+N24W004
+N24W005
+N24W006
+N24W007
+N24W008
+N24W009
+N24W010
+N24W011
+N24W012
+N24W013
+N24W014
+N24W015
+N24W016
+N25E000
+N25E001
+N25E002
+N25E003
+N25E004
+N25E005
+N25E006
+N25E007
+N25E008
+N25E009
+N25E010
+N25E011
+N25E012
+N25E013
+N25E014
+N25E015
+N25E016
+N25E017
+N25E018
+N25E019
+N25E020
+N25E021
+N25E022
+N25E023
+N25E024
+N25E025
+N25E026
+N25E027
+N25E028
+N25E029
+N25E030
+N25E031
+N25E032
+N25E033
+N25E034
+N25E036
+N25E037
+N25E038
+N25E039
+N25E040
+N25E041
+N25E042
+N25E043
+N25E044
+N25E045
+N25E046
+N25E047
+N25E048
+N25E049
+N25E050
+N25E051
+N25E052
+N25E054
+N25E055
+N25E056
+N25E057
+N25E058
+N25E059
+N25W001
+N25W002
+N25W003
+N25W004
+N25W005
+N25W006
+N25W007
+N25W008
+N25W009
+N25W010
+N25W011
+N25W012
+N25W013
+N25W014
+N25W015
+N26E000
+N26E001
+N26E002
+N26E003
+N26E004
+N26E005
+N26E006
+N26E007
+N26E008
+N26E009
+N26E010
+N26E011
+N26E012
+N26E013
+N26E014
+N26E015
+N26E016
+N26E017
+N26E018
+N26E019
+N26E020
+N26E021
+N26E022
+N26E023
+N26E024
+N26E025
+N26E026
+N26E027
+N26E028
+N26E029
+N26E030
+N26E031
+N26E032
+N26E033
+N26E034
+N26E035
+N26E036
+N26E037
+N26E038
+N26E039
+N26E040
+N26E041
+N26E042
+N26E043
+N26E044
+N26E045
+N26E046
+N26E047
+N26E048
+N26E049
+N26E050
+N26E051
+N26E053
+N26E054
+N26E055
+N26E056
+N26E057
+N26E058
+N26E059
+N26W001
+N26W002
+N26W003
+N26W004
+N26W005
+N26W006
+N26W007
+N26W008
+N26W009
+N26W010
+N26W011
+N26W012
+N26W013
+N26W014
+N26W015
+N27E000
+N27E001
+N27E002
+N27E003
+N27E004
+N27E005
+N27E006
+N27E007
+N27E008
+N27E009
+N27E010
+N27E011
+N27E012
+N27E013
+N27E014
+N27E015
+N27E016
+N27E017
+N27E018
+N27E019
+N27E020
+N27E021
+N27E022
+N27E023
+N27E024
+N27E025
+N27E026
+N27E027
+N27E028
+N27E029
+N27E030
+N27E031
+N27E032
+N27E033
+N27E034
+N27E035
+N27E036
+N27E037
+N27E038
+N27E039
+N27E040
+N27E041
+N27E042
+N27E043
+N27E044
+N27E045
+N27E046
+N27E047
+N27E048
+N27E049
+N27E050
+N27E051
+N27E052
+N27E053
+N27E054
+N27E055
+N27E056
+N27E057
+N27E058
+N27E059
+N27W001
+N27W002
+N27W003
+N27W004
+N27W005
+N27W006
+N27W007
+N27W008
+N27W009
+N27W010
+N27W011
+N27W012
+N27W013
+N27W014
+N27W016
+N27W017
+N27W018
+N27W019
+N28E000
+N28E001
+N28E002
+N28E003
+N28E004
+N28E005
+N28E006
+N28E007
+N28E008
+N28E009
+N28E010
+N28E011
+N28E012
+N28E013
+N28E014
+N28E015
+N28E016
+N28E017
+N28E018
+N28E019
+N28E020
+N28E021
+N28E022
+N28E023
+N28E024
+N28E025
+N28E026
+N28E027
+N28E028
+N28E029
+N28E030
+N28E031
+N28E032
+N28E033
+N28E034
+N28E035
+N28E036
+N28E037
+N28E038
+N28E039
+N28E040
+N28E041
+N28E042
+N28E043
+N28E044
+N28E045
+N28E046
+N28E047
+N28E048
+N28E050
+N28E051
+N28E052
+N28E053
+N28E054
+N28E055
+N28E056
+N28E057
+N28E058
+N28E059
+N28W001
+N28W002
+N28W003
+N28W004
+N28W005
+N28W006
+N28W007
+N28W008
+N28W009
+N28W010
+N28W011
+N28W012
+N28W013
+N28W014
+N28W015
+N28W016
+N28W017
+N28W018
+N28W019
+N29E000
+N29E001
+N29E002
+N29E003
+N29E004
+N29E005
+N29E006
+N29E007
+N29E008
+N29E009
+N29E010
+N29E011
+N29E012
+N29E013
+N29E014
+N29E015
+N29E016
+N29E017
+N29E018
+N29E019
+N29E020
+N29E021
+N29E022
+N29E023
+N29E024
+N29E025
+N29E026
+N29E027
+N29E028
+N29E029
+N29E030
+N29E031
+N29E032
+N29E033
+N29E034
+N29E035
+N29E036
+N29E037
+N29E038
+N29E039
+N29E040
+N29E041
+N29E042
+N29E043
+N29E044
+N29E045
+N29E046
+N29E047
+N29E048
+N29E049
+N29E050
+N29E051
+N29E052
+N29E053
+N29E054
+N29E055
+N29E056
+N29E057
+N29E058
+N29E059
+N29W001
+N29W002
+N29W003
+N29W004
+N29W005
+N29W006
+N29W007
+N29W008
+N29W009
+N29W010
+N29W011
+N29W014
+N30E000
+N30E001
+N30E002
+N30E003
+N30E004
+N30E005
+N30E006
+N30E007
+N30E008
+N30E009
+N30E010
+N30E011
+N30E012
+N30E013
+N30E014
+N30E015
+N30E016
+N30E017
+N30E018
+N30E019
+N30E020
+N30E021
+N30E022
+N30E023
+N30E024
+N30E025
+N30E026
+N30E027
+N30E028
+N30E029
+N30E030
+N30E031
+N30E032
+N30E033
+N30E034
+N30E035
+N30E036
+N30E037
+N30E038
+N30E039
+N30E040
+N30E041
+N30E042
+N30E043
+N30E044
+N30E045
+N30E046
+N30E047
+N30E048
+N30E049
+N30E050
+N30E051
+N30E052
+N30E053
+N30E054
+N30E055
+N30E056
+N30E057
+N30E058
+N30E059
+N30W001
+N30W002
+N30W003
+N30W004
+N30W005
+N30W006
+N30W007
+N30W008
+N30W009
+N30W010
+N30W016
+N30W017
+N31E000
+N31E001
+N31E002
+N31E003
+N31E004
+N31E005
+N31E006
+N31E007
+N31E008
+N31E009
+N31E010
+N31E011
+N31E012
+N31E013
+N31E014
+N31E015
+N31E016
+N31E017
+N31E019
+N31E020
+N31E021
+N31E022
+N31E023
+N31E024
+N31E025
+N31E026
+N31E027
+N31E028
+N31E029
+N31E030
+N31E031
+N31E032
+N31E033
+N31E034
+N31E035
+N31E036
+N31E037
+N31E038
+N31E039
+N31E040
+N31E041
+N31E042
+N31E043
+N31E044
+N31E045
+N31E046
+N31E047
+N31E048
+N31E049
+N31E050
+N31E051
+N31E052
+N31E053
+N31E054
+N31E055
+N31E056
+N31E057
+N31E058
+N31E059
+N31W001
+N31W002
+N31W003
+N31W004
+N31W005
+N31W006
+N31W007
+N31W008
+N31W009
+N31W010
+N32E000
+N32E001
+N32E002
+N32E003
+N32E004
+N32E005
+N32E006
+N32E007
+N32E008
+N32E009
+N32E010
+N32E011
+N32E012
+N32E013
+N32E014
+N32E015
+N32E019
+N32E020
+N32E021
+N32E022
+N32E023
+N32E024
+N32E034
+N32E035
+N32E036
+N32E037
+N32E038
+N32E039
+N32E040
+N32E041
+N32E042
+N32E043
+N32E044
+N32E045
+N32E046
+N32E047
+N32E048
+N32E049
+N32E050
+N32E051
+N32E052
+N32E053
+N32E054
+N32E055
+N32E056
+N32E057
+N32E058
+N32E059
+N32W001
+N32W002
+N32W003
+N32W004
+N32W005
+N32W006
+N32W007
+N32W008
+N32W009
+N32W010
+N32W017
+N32W018
+N33E000
+N33E001
+N33E002
+N33E003
+N33E004
+N33E005
+N33E006
+N33E007
+N33E008
+N33E009
+N33E010
+N33E011
+N33E035
+N33E036
+N33E037
+N33E038
+N33E039
+N33E040
+N33E041
+N33E042
+N33E043
+N33E044
+N33E045
+N33E046
+N33E047
+N33E048
+N33E049
+N33E050
+N33E051
+N33E052
+N33E053
+N33E054
+N33E055
+N33E056
+N33E057
+N33E058
+N33E059
+N33W001
+N33W002
+N33W003
+N33W004
+N33W005
+N33W006
+N33W007
+N33W008
+N33W009
+N33W017
+N34E000
+N34E001
+N34E002
+N34E003
+N34E004
+N34E005
+N34E006
+N34E007
+N34E008
+N34E009
+N34E010
+N34E011
+N34E023
+N34E024
+N34E025
+N34E026
+N34E032
+N34E033
+N34E034
+N34E035
+N34E036
+N34E037
+N34E038
+N34E039
+N34E040
+N34E041
+N34E042
+N34E043
+N34E044
+N34E045
+N34E046
+N34E047
+N34E048
+N34E049
+N34E050
+N34E051
+N34E052
+N34E053
+N34E054
+N34E055
+N34E056
+N34E057
+N34E058
+N34E059
+N34W001
+N34W002
+N34W003
+N34W004
+N34W005
+N34W006
+N34W007
+N36W026
+N37W025
+N37W026
+N38W028
+N38W029
+N39W028
+N39W029
+N39W032
+S01E006
+S01E008
+S01E009
+S01E010
+S01E011
+S01E012
+S01E013
+S01E014
+S01E015
+S01E016
+S01E017
+S01E018
+S01E019
+S01E020
+S01E021
+S01E022
+S01E023
+S01E024
+S01E025
+S01E026
+S01E027
+S01E028
+S01E029
+S01E030
+S01E031
+S01E032
+S01E033
+S01E034
+S01E035
+S01E036
+S01E037
+S01E038
+S01E039
+S01E040
+S01E041
+S01E042
+S02E005
+S02E008
+S02E009
+S02E010
+S02E011
+S02E012
+S02E013
+S02E014
+S02E015
+S02E016
+S02E017
+S02E018
+S02E019
+S02E020
+S02E021
+S02E022
+S02E023
+S02E024
+S02E025
+S02E026
+S02E027
+S02E028
+S02E029
+S02E030
+S02E031
+S02E032
+S02E033
+S02E034
+S02E035
+S02E036
+S02E037
+S02E038
+S02E039
+S02E040
+S02E041
+S02E042
+S03E009
+S03E010
+S03E011
+S03E012
+S03E013
+S03E014
+S03E015
+S03E016
+S03E017
+S03E018
+S03E019
+S03E020
+S03E021
+S03E022
+S03E023
+S03E024
+S03E025
+S03E026
+S03E027
+S03E028
+S03E029
+S03E030
+S03E031
+S03E032
+S03E033
+S03E034
+S03E035
+S03E036
+S03E037
+S03E038
+S03E039
+S03E040
+S03E041
+S04E010
+S04E011
+S04E012
+S04E013
+S04E014
+S04E015
+S04E016
+S04E017
+S04E018
+S04E019
+S04E020
+S04E021
+S04E022
+S04E023
+S04E024
+S04E025
+S04E026
+S04E027
+S04E028
+S04E029
+S04E030
+S04E031
+S04E032
+S04E033
+S04E034
+S04E035
+S04E036
+S04E037
+S04E038
+S04E039
+S04E040
+S04E055
+S05E011
+S05E012
+S05E013
+S05E014
+S05E015
+S05E016
+S05E017
+S05E018
+S05E019
+S05E020
+S05E021
+S05E022
+S05E023
+S05E024
+S05E025
+S05E026
+S05E027
+S05E028
+S05E029
+S05E030
+S05E031
+S05E032
+S05E033
+S05E034
+S05E035
+S05E036
+S05E037
+S05E038
+S05E039
+S05E053
+S05E055
+S06E011
+S06E012
+S06E013
+S06E014
+S06E015
+S06E016
+S06E017
+S06E018
+S06E019
+S06E020
+S06E021
+S06E022
+S06E023
+S06E024
+S06E025
+S06E026
+S06E027
+S06E028
+S06E029
+S06E030
+S06E031
+S06E032
+S06E033
+S06E034
+S06E035
+S06E036
+S06E037
+S06E038
+S06E039
+S06E053
+S06E055
+S07E012
+S07E013
+S07E014
+S07E015
+S07E016
+S07E017
+S07E018
+S07E019
+S07E020
+S07E021
+S07E022
+S07E023
+S07E024
+S07E025
+S07E026
+S07E027
+S07E028
+S07E029
+S07E030
+S07E031
+S07E032
+S07E033
+S07E034
+S07E035
+S07E036
+S07E037
+S07E038
+S07E039
+S07E052
+S07E053
+S08E012
+S08E013
+S08E014
+S08E015
+S08E016
+S08E017
+S08E018
+S08E019
+S08E020
+S08E021
+S08E022
+S08E023
+S08E024
+S08E025
+S08E026
+S08E027
+S08E028
+S08E029
+S08E030
+S08E031
+S08E032
+S08E033
+S08E034
+S08E035
+S08E036
+S08E037
+S08E038
+S08E039
+S08E052
+S08E056
+S09E013
+S09E014
+S09E015
+S09E016
+S09E017
+S09E018
+S09E019
+S09E020
+S09E021
+S09E022
+S09E023
+S09E024
+S09E025
+S09E026
+S09E027
+S09E028
+S09E029
+S09E030
+S09E031
+S09E032
+S09E033
+S09E034
+S09E035
+S09E036
+S09E037
+S09E038
+S09E039
+S10E012
+S10E013
+S10E014
+S10E015
+S10E016
+S10E017
+S10E018
+S10E019
+S10E020
+S10E021
+S10E022
+S10E023
+S10E024
+S10E025
+S10E026
+S10E027
+S10E028
+S10E029
+S10E030
+S10E031
+S10E032
+S10E033
+S10E034
+S10E035
+S10E036
+S10E037
+S10E038
+S10E039
+S10E046
+S10E047
+S10E050
+S10E051
+S11E013
+S11E014
+S11E015
+S11E016
+S11E017
+S11E018
+S11E019
+S11E020
+S11E021
+S11E022
+S11E023
+S11E024
+S11E025
+S11E026
+S11E027
+S11E028
+S11E029
+S11E030
+S11E031
+S11E032
+S11E033
+S11E034
+S11E035
+S11E036
+S11E037
+S11E038
+S11E039
+S11E040
+S11E047
+S11E051
+S11E056
+S12E013
+S12E014
+S12E015
+S12E016
+S12E017
+S12E018
+S12E019
+S12E020
+S12E021
+S12E022
+S12E023
+S12E024
+S12E025
+S12E026
+S12E027
+S12E028
+S12E029
+S12E030
+S12E031
+S12E032
+S12E033
+S12E034
+S12E035
+S12E036
+S12E037
+S12E038
+S12E039
+S12E040
+S12E043
+S12E047
+S12E049
+S13E012
+S13E013
+S13E014
+S13E015
+S13E016
+S13E017
+S13E018
+S13E019
+S13E020
+S13E021
+S13E022
+S13E023
+S13E024
+S13E025
+S13E026
+S13E027
+S13E028
+S13E029
+S13E030
+S13E031
+S13E032
+S13E033
+S13E034
+S13E035
+S13E036
+S13E037
+S13E038
+S13E039
+S13E040
+S13E043
+S13E044
+S13E045
+S13E048
+S13E049
+S14E012
+S14E013
+S14E014
+S14E015
+S14E016
+S14E017
+S14E018
+S14E019
+S14E020
+S14E021
+S14E022
+S14E023
+S14E024
+S14E025
+S14E026
+S14E027
+S14E028
+S14E029
+S14E030
+S14E031
+S14E032
+S14E033
+S14E034
+S14E035
+S14E036
+S14E037
+S14E038
+S14E039
+S14E040
+S14E045
+S14E047
+S14E048
+S14E049
+S14E050
+S15E012
+S15E013
+S15E014
+S15E015
+S15E016
+S15E017
+S15E018
+S15E019
+S15E020
+S15E021
+S15E022
+S15E023
+S15E024
+S15E025
+S15E026
+S15E027
+S15E028
+S15E029
+S15E030
+S15E031
+S15E032
+S15E033
+S15E034
+S15E035
+S15E036
+S15E037
+S15E038
+S15E039
+S15E040
+S15E047
+S15E048
+S15E049
+S15E050
+S16E011
+S16E012
+S16E013
+S16E014
+S16E015
+S16E016
+S16E017
+S16E018
+S16E019
+S16E020
+S16E021
+S16E022
+S16E023
+S16E024
+S16E025
+S16E026
+S16E027
+S16E028
+S16E029
+S16E030
+S16E031
+S16E032
+S16E033
+S16E034
+S16E035
+S16E036
+S16E037
+S16E038
+S16E039
+S16E040
+S16E045
+S16E046
+S16E047
+S16E048
+S16E049
+S16E050
+S16E054
+S17E011
+S17E012
+S17E013
+S17E014
+S17E015
+S17E016
+S17E017
+S17E018
+S17E019
+S17E020
+S17E021
+S17E022
+S17E023
+S17E024
+S17E025
+S17E026
+S17E027
+S17E028
+S17E029
+S17E030
+S17E031
+S17E032
+S17E033
+S17E034
+S17E035
+S17E036
+S17E037
+S17E038
+S17E039
+S17E040
+S17E043
+S17E044
+S17E045
+S17E046
+S17E047
+S17E048
+S17E049
+S17E050
+S17E059
+S18E011
+S18E012
+S18E013
+S18E014
+S18E015
+S18E016
+S18E017
+S18E018
+S18E019
+S18E020
+S18E021
+S18E022
+S18E023
+S18E024
+S18E025
+S18E026
+S18E027
+S18E028
+S18E029
+S18E030
+S18E031
+S18E032
+S18E033
+S18E034
+S18E035
+S18E036
+S18E037
+S18E038
+S18E039
+S18E042
+S18E043
+S18E044
+S18E045
+S18E046
+S18E047
+S18E048
+S18E049
+S19E011
+S19E012
+S19E013
+S19E014
+S19E015
+S19E016
+S19E017
+S19E018
+S19E019
+S19E020
+S19E021
+S19E022
+S19E023
+S19E024
+S19E025
+S19E026
+S19E027
+S19E028
+S19E029
+S19E030
+S19E031
+S19E032
+S19E033
+S19E034
+S19E035
+S19E036
+S19E037
+S19E043
+S19E044
+S19E045
+S19E046
+S19E047
+S19E048
+S19E049
+S20E012
+S20E013
+S20E014
+S20E015
+S20E016
+S20E017
+S20E018
+S20E019
+S20E020
+S20E021
+S20E022
+S20E023
+S20E024
+S20E025
+S20E026
+S20E027
+S20E028
+S20E029
+S20E030
+S20E031
+S20E032
+S20E033
+S20E034
+S20E035
+S20E044
+S20E045
+S20E046
+S20E047
+S20E048
+S20E049
+S20E057
+S20E063
+S21E013
+S21E014
+S21E015
+S21E016
+S21E017
+S21E018
+S21E019
+S21E020
+S21E021
+S21E022
+S21E023
+S21E024
+S21E025
+S21E026
+S21E027
+S21E028
+S21E029
+S21E030
+S21E031
+S21E032
+S21E033
+S21E034
+S21E035
+S21E043
+S21E044
+S21E045
+S21E046
+S21E047
+S21E048
+S21E055
+S21E057
+S22E013
+S22E014
+S22E015
+S22E016
+S22E017
+S22E018
+S22E019
+S22E020
+S22E021
+S22E022
+S22E023
+S22E024
+S22E025
+S22E026
+S22E027
+S22E028
+S22E029
+S22E030
+S22E031
+S22E032
+S22E033
+S22E034
+S22E035
+S22E043
+S22E044
+S22E045
+S22E046
+S22E047
+S22E048
+S22E055
+S23E014
+S23E015
+S23E016
+S23E017
+S23E018
+S23E019
+S23E020
+S23E021
+S23E022
+S23E023
+S23E024
+S23E025
+S23E026
+S23E027
+S23E028
+S23E029
+S23E030
+S23E031
+S23E032
+S23E033
+S23E034
+S23E035
+S23E040
+S23E043
+S23E044
+S23E045
+S23E046
+S23E047
+S23E048
+S24E014
+S24E015
+S24E016
+S24E017
+S24E018
+S24E019
+S24E020
+S24E021
+S24E022
+S24E023
+S24E024
+S24E025
+S24E026
+S24E027
+S24E028
+S24E029
+S24E030
+S24E031
+S24E032
+S24E033
+S24E034
+S24E035
+S24E043
+S24E044
+S24E045
+S24E046
+S24E047
+S25E014
+S25E015
+S25E016
+S25E017
+S25E018
+S25E019
+S25E020
+S25E021
+S25E022
+S25E023
+S25E024
+S25E025
+S25E026
+S25E027
+S25E028
+S25E029
+S25E030
+S25E031
+S25E032
+S25E033
+S25E034
+S25E035
+S25E043
+S25E044
+S25E045
+S25E046
+S25E047
+S26E014
+S26E015
+S26E016
+S26E017
+S26E018
+S26E019
+S26E020
+S26E021
+S26E022
+S26E023
+S26E024
+S26E025
+S26E026
+S26E027
+S26E028
+S26E029
+S26E030
+S26E031
+S26E032
+S26E033
+S26E034
+S26E044
+S26E045
+S26E046
+S26E047
+S27E014
+S27E015
+S27E016
+S27E017
+S27E018
+S27E019
+S27E020
+S27E021
+S27E022
+S27E023
+S27E024
+S27E025
+S27E026
+S27E027
+S27E028
+S27E029
+S27E030
+S27E031
+S27E032
+S28E015
+S28E016
+S28E017
+S28E018
+S28E019
+S28E020
+S28E021
+S28E022
+S28E023
+S28E024
+S28E025
+S28E026
+S28E027
+S28E028
+S28E029
+S28E030
+S28E031
+S28E032
+S29E015
+S29E016
+S29E017
+S29E018
+S29E019
+S29E020
+S29E021
+S29E022
+S29E023
+S29E024
+S29E025
+S29E026
+S29E027
+S29E028
+S29E029
+S29E030
+S29E031
+S29E032
+S30E016
+S30E017
+S30E018
+S30E019
+S30E020
+S30E021
+S30E022
+S30E023
+S30E024
+S30E025
+S30E026
+S30E027
+S30E028
+S30E029
+S30E030
+S30E031
+S31E017
+S31E018
+S31E019
+S31E020
+S31E021
+S31E022
+S31E023
+S31E024
+S31E025
+S31E026
+S31E027
+S31E028
+S31E029
+S31E030
+S32E017
+S32E018
+S32E019
+S32E020
+S32E021
+S32E022
+S32E023
+S32E024
+S32E025
+S32E026
+S32E027
+S32E028
+S32E029
+S32E030
+S33E017
+S33E018
+S33E019
+S33E020
+S33E021
+S33E022
+S33E023
+S33E024
+S33E025
+S33E026
+S33E027
+S33E028
+S33E029
+S34E017
+S34E018
+S34E019
+S34E020
+S34E021
+S34E022
+S34E023
+S34E024
+S34E025
+S34E026
+S34E027
+S35E018
+S35E019
+S35E020
+S35E021
+S35E022
+S35E023
+S35E024
+S35E025
+
diff --git a/tim/prune/function/srtm/srtmtiles.dat b/tim/prune/function/srtm/srtmtiles.dat
new file mode 100644 (file)
index 0000000..36ebbf5
Binary files /dev/null and b/tim/prune/function/srtm/srtmtiles.dat differ
index 5e31a4e97aee5086ba60d184bc69e6e6d276d0be..9cfd7cee703d9039bc4d520ab2888b0de89100ed 100644 (file)
@@ -22,6 +22,7 @@ import tim.prune.DataSubscriber;
 import tim.prune.FunctionLibrary;
 import tim.prune.GenericFunction;
 import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
 import tim.prune.config.Config;
 import tim.prune.data.Altitude;
 import tim.prune.data.Coordinate;
@@ -214,8 +215,8 @@ public class DetailsDisplay extends GenericDisplay
                _distUnitsDropdown.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
-                               dataUpdated(DataSubscriber.UNITS_CHANGED);
                                Config.setConfigBoolean(Config.KEY_METRIC_UNITS, _distUnitsDropdown.getSelectedIndex() == 0);
+                               UpdateMessageBroker.informSubscribers(DataSubscriber.UNITS_CHANGED);
                        }
                });
                lowerPanel.add(_distUnitsDropdown);
@@ -405,7 +406,12 @@ public class DetailsDisplay extends GenericDisplay
                        default: // just as it was
                                coord = inCoordinate.output(Coordinate.FORMAT_NONE);
                }
-               return inPrefix + coord;
+               // Fix broken degree signs (due to unicode mangling)
+               final char brokenDeg = 65533;
+               if (coord.indexOf(brokenDeg) >= 0) {
+                       coord = coord.replaceAll(String.valueOf(brokenDeg), "\u00B0");
+               }
+               return inPrefix + restrictDP(coord);
        }
 
 
@@ -430,6 +436,25 @@ public class DetailsDisplay extends GenericDisplay
                return _distanceFormatter.format(inDist);
        }
 
+       /**
+        * Restrict the given coordinate to a limited number of decimal places for display
+        * @param inCoord coordinate string
+        * @return chopped string
+        */
+       private static String restrictDP(String inCoord)
+       {
+               final int DECIMAL_PLACES = 7;
+               if (inCoord == null) return "";
+               final int dotPos = Math.max(inCoord.lastIndexOf('.'), inCoord.lastIndexOf(','));
+               if (dotPos >= 0) {
+                       final int chopPos = dotPos + DECIMAL_PLACES;
+                       if (chopPos < (inCoord.length()-1)) {
+                               return inCoord.substring(0, chopPos);
+                       }
+               }
+               return inCoord;
+       }
+
        /**
         * Create a little button for rotating the current photo
         * @param inIcon icon to use (from IconManager)
index f34afd724c20f199c28f029ef5b98d34ac877958..df706b74e17c754661ebc164b22a8adf2724b56c 100644 (file)
@@ -22,7 +22,7 @@ public abstract class DisplayUtils
                        + " " + ((inNumSecs / 60) % 60) + I18nManager.getText("display.range.time.mins");
                if (inNumSecs < 432000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days")
                        + " " + (inNumSecs / 60 / 60) % 24 + I18nManager.getText("display.range.time.hours");
-               if (inNumSecs < 8640000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days");
+               if (inNumSecs < 86400000L) return "" + (inNumSecs / 86400L) + I18nManager.getText("display.range.time.days");
                return "big";
        }
 }
diff --git a/tim/prune/gui/GenericChart.java b/tim/prune/gui/GenericChart.java
deleted file mode 100644 (file)
index ae2feac..0000000
+++ /dev/null
@@ -1,110 +0,0 @@
-package tim.prune.gui;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.event.MouseEvent;
-import java.awt.event.MouseListener;
-
-import tim.prune.I18nManager;
-import tim.prune.config.ColourScheme;
-import tim.prune.config.Config;
-import tim.prune.data.TrackInfo;
-
-
-/**
- * Generic chart component to form baseclass for map and profile charts
- */
-public abstract class GenericChart extends GenericDisplay implements MouseListener
-{
-       protected Dimension MINIMUM_SIZE = new Dimension(200, 250);
-       protected static final int BORDER_WIDTH = 8;
-
-       // Colours
-       private static final Color COLOR_NODATA_TEXT = Color.GRAY;
-
-
-       /**
-        * Constructor
-        * @param inTrackInfo track info object
-        */
-       protected GenericChart(TrackInfo inTrackInfo)
-       {
-               super(inTrackInfo);
-       }
-
-       /**
-        * Override minimum size method to restrict map
-        */
-       public Dimension getMinimumSize()
-       {
-               return MINIMUM_SIZE;
-       }
-
-       /**
-        * Override paint method to draw map
-        * @param inG graphics object
-        */
-       public void paint(Graphics inG)
-       {
-               super.paint(inG);
-               int width = getWidth();
-               int height = getHeight();
-               // Get colours
-               ColourScheme colourScheme = Config.getColourScheme();
-               final Color borderColour = colourScheme.getColour(ColourScheme.IDX_BORDERS);
-               final Color backgroundColour = colourScheme.getColour(ColourScheme.IDX_BACKGROUND);
-               final Color insideColour = backgroundColour;
-               // border background
-               inG.setColor(backgroundColour);
-               inG.fillRect(0, 0, width, height);
-               if (width < 2*BORDER_WIDTH || height < 2*BORDER_WIDTH) return;
-               // blank graph area, with line border
-               inG.setColor(insideColour);
-               inG.fillRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
-               // Display message if no data to be displayed
-               if (_track == null || _track.getNumPoints() <= 0)
-               {
-                       inG.setColor(COLOR_NODATA_TEXT);
-                       inG.drawString(I18nManager.getText("display.nodata"), 50, height/2);
-               }
-               else {
-                       inG.setColor(borderColour);
-                       inG.drawRect(BORDER_WIDTH, BORDER_WIDTH, width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH);
-               }
-       }
-
-
-       /**
-        * Method to inform map that data has changed
-        */
-       public void dataUpdated(byte inUpdateType)
-       {
-               repaint();
-       }
-
-
-       /**
-        * mouse enter events ignored
-        */
-       public void mouseEntered(MouseEvent e)
-       {}
-
-       /**
-        * mouse exit events ignored
-        */
-       public void mouseExited(MouseEvent e)
-       {}
-
-       /**
-        * ignore mouse pressed for now too
-        */
-       public void mousePressed(MouseEvent e)
-       {}
-
-       /**
-        * and also ignore mouse released
-        */
-       public void mouseReleased(MouseEvent e)
-       {}
-}
index 998a533ce4a73f58c1ae43cb95a2e5af84a24b7a..1cca456e2271b5979b9e9e59355857521191d3e4 100644 (file)
@@ -1,8 +1,8 @@
 package tim.prune.gui;
 
+import java.awt.Toolkit;
 import java.awt.event.ActionEvent;
 import java.awt.event.ActionListener;
-import java.awt.event.InputEvent;
 import java.awt.event.KeyEvent;
 
 import javax.swing.JButton;
@@ -73,6 +73,7 @@ public class MenuManager implements DataSubscriber
        private JMenu     _browserMapMenu = null;
        private JMenuItem _chartItem = null;
        private JMenuItem _getGpsiesItem = null;
+       private JMenuItem _lookupSrtmItem = null;
        private JMenuItem _distanceItem = null;
        private JMenuItem _fullRangeDetailsItem = null;
        private JMenuItem _saveExifItem = null;
@@ -84,6 +85,7 @@ public class MenuManager implements DataSubscriber
        private JMenuItem _rotatePhotoLeft = null;
        private JMenuItem _rotatePhotoRight = null;
        private JMenuItem _ignoreExifThumb = null;
+       private JCheckBoxMenuItem _onlineCheckbox = null;
 
        // ActionListeners for reuse by menu and toolbar
        private ActionListener _openFileAction = null;
@@ -140,7 +142,7 @@ public class MenuManager implements DataSubscriber
                JMenu fileMenu = new JMenu(I18nManager.getText("menu.file"));
                setAltKey(fileMenu, "altkey.menu.file");
                // Open file
-               JMenuItem openMenuItem = new JMenuItem(I18nManager.getText("menu.file.open"));
+               JMenuItem openMenuItem = new JMenuItem(I18nManager.getText("function.open"));
                setShortcut(openMenuItem, "shortcut.menu.file.open");
                _openFileAction = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -207,8 +209,8 @@ public class MenuManager implements DataSubscriber
                // Track menu
                JMenu trackMenu = new JMenu(I18nManager.getText("menu.track"));
                setAltKey(trackMenu, "altkey.menu.track");
-               _undoItem = new JMenuItem(I18nManager.getText("menu.edit.undo"));
-               setShortcut(_undoItem, "shortcut.menu.edit.undo");
+               _undoItem = new JMenuItem(I18nManager.getText("menu.track.undo"));
+               setShortcut(_undoItem, "shortcut.menu.track.undo");
                _undoAction = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -218,7 +220,7 @@ public class MenuManager implements DataSubscriber
                _undoItem.addActionListener(_undoAction);
                _undoItem.setEnabled(false);
                trackMenu.add(_undoItem);
-               _clearUndoItem = new JMenuItem(I18nManager.getText("menu.edit.clearundo"));
+               _clearUndoItem = new JMenuItem(I18nManager.getText("menu.track.clearundo"));
                _clearUndoItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -232,7 +234,7 @@ public class MenuManager implements DataSubscriber
                setShortcut(_compressItem, "shortcut.menu.edit.compress");
                _compressItem.setEnabled(false);
                trackMenu.add(_compressItem);
-               _deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.edit.deletemarked"));
+               _deleteMarkedPointsItem = new JMenuItem(I18nManager.getText("menu.track.deletemarked"));
                _deleteMarkedPointsItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -243,9 +245,9 @@ public class MenuManager implements DataSubscriber
                trackMenu.add(_deleteMarkedPointsItem);
                trackMenu.addSeparator();
                // Rearrange waypoints
-               _rearrangeMenu = new JMenu(I18nManager.getText("menu.edit.rearrange"));
+               _rearrangeMenu = new JMenu(I18nManager.getText("menu.track.rearrange"));
                _rearrangeMenu.setEnabled(false);
-               JMenuItem  rearrangeStartItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.start"));
+               JMenuItem  rearrangeStartItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.start"));
                rearrangeStartItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -254,7 +256,7 @@ public class MenuManager implements DataSubscriber
                });
                rearrangeStartItem.setEnabled(true);
                _rearrangeMenu.add(rearrangeStartItem);
-               JMenuItem rearrangeEndItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.end"));
+               JMenuItem rearrangeEndItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.end"));
                rearrangeEndItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -263,7 +265,7 @@ public class MenuManager implements DataSubscriber
                });
                rearrangeEndItem.setEnabled(true);
                _rearrangeMenu.add(rearrangeEndItem);
-               JMenuItem rearrangeNearestItem = new JMenuItem(I18nManager.getText("menu.edit.rearrange.nearest"));
+               JMenuItem rearrangeNearestItem = new JMenuItem(I18nManager.getText("menu.track.rearrange.nearest"));
                rearrangeNearestItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -277,13 +279,16 @@ public class MenuManager implements DataSubscriber
                _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES);
                _getGpsiesItem.setEnabled(false);
                trackMenu.add(_getGpsiesItem);
+               _lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM);
+               _lookupSrtmItem.setEnabled(false);
+               trackMenu.add(_lookupSrtmItem);
                menubar.add(trackMenu);
 
                // Range menu
                JMenu rangeMenu = new JMenu(I18nManager.getText("menu.range"));
                setAltKey(rangeMenu, "altkey.menu.range");
-               _selectAllItem = new JMenuItem(I18nManager.getText("menu.select.all"));
-               setShortcut(_selectAllItem, "shortcut.menu.select.all");
+               _selectAllItem = new JMenuItem(I18nManager.getText("menu.range.all"));
+               setShortcut(_selectAllItem, "shortcut.menu.range.all");
                _selectAllItem.setEnabled(false);
                _selectAllItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -292,7 +297,7 @@ public class MenuManager implements DataSubscriber
                        }
                });
                rangeMenu.add(_selectAllItem);
-               _selectNoneItem = new JMenuItem(I18nManager.getText("menu.select.none"));
+               _selectNoneItem = new JMenuItem(I18nManager.getText("menu.range.none"));
                _selectNoneItem.setEnabled(false);
                _selectNoneItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -302,7 +307,7 @@ public class MenuManager implements DataSubscriber
                });
                rangeMenu.add(_selectNoneItem);
                rangeMenu.addSeparator();
-               _selectStartItem = new JMenuItem(I18nManager.getText("menu.select.start"));
+               _selectStartItem = new JMenuItem(I18nManager.getText("menu.range.start"));
                _selectStartItem.setEnabled(false);
                _selectStartAction = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -312,7 +317,7 @@ public class MenuManager implements DataSubscriber
                };
                _selectStartItem.addActionListener(_selectStartAction);
                rangeMenu.add(_selectStartItem);
-               _selectEndItem = new JMenuItem(I18nManager.getText("menu.select.end"));
+               _selectEndItem = new JMenuItem(I18nManager.getText("menu.range.end"));
                _selectEndItem.setEnabled(false);
                _selectEndAction = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
@@ -323,7 +328,7 @@ public class MenuManager implements DataSubscriber
                _selectEndItem.addActionListener(_selectEndAction);
                rangeMenu.add(_selectEndItem);
                rangeMenu.addSeparator();
-               _deleteRangeItem = new JMenuItem(I18nManager.getText("menu.edit.deleterange"));
+               _deleteRangeItem = new JMenuItem(I18nManager.getText("menu.range.deleterange"));
                _deleteRangeAction = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -333,7 +338,7 @@ public class MenuManager implements DataSubscriber
                _deleteRangeItem.addActionListener(_deleteRangeAction);
                _deleteRangeItem.setEnabled(false);
                rangeMenu.add(_deleteRangeItem);
-               _reverseItem = new JMenuItem(I18nManager.getText("menu.edit.reverse"));
+               _reverseItem = new JMenuItem(I18nManager.getText("menu.range.reverse"));
                _reverseItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -348,7 +353,7 @@ public class MenuManager implements DataSubscriber
                _addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET);
                _addAltitudeOffsetItem.setEnabled(false);
                rangeMenu.add(_addAltitudeOffsetItem);
-               _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.edit.mergetracksegments"));
+               _mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.range.mergetracksegments"));
                _mergeSegmentsItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -358,7 +363,7 @@ public class MenuManager implements DataSubscriber
                _mergeSegmentsItem.setEnabled(false);
                rangeMenu.add(_mergeSegmentsItem);
                rangeMenu.addSeparator();
-               _interpolateItem = new JMenuItem(I18nManager.getText("menu.edit.interpolate"));
+               _interpolateItem = new JMenuItem(I18nManager.getText("menu.range.interpolate"));
                _interpolateItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -367,7 +372,7 @@ public class MenuManager implements DataSubscriber
                });
                _interpolateItem.setEnabled(false);
                rangeMenu.add(_interpolateItem);
-               _averageItem = new JMenuItem(I18nManager.getText("menu.edit.average"));
+               _averageItem = new JMenuItem(I18nManager.getText("menu.range.average"));
                _averageItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -376,7 +381,7 @@ public class MenuManager implements DataSubscriber
                });
                _averageItem.setEnabled(false);
                rangeMenu.add(_averageItem);
-               _cutAndMoveItem = new JMenuItem(I18nManager.getText("menu.edit.cutandmove"));
+               _cutAndMoveItem = new JMenuItem(I18nManager.getText("menu.range.cutandmove"));
                _cutAndMoveItem.addActionListener(new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -393,7 +398,7 @@ public class MenuManager implements DataSubscriber
                // Point menu
                JMenu pointMenu = new JMenu(I18nManager.getText("menu.point"));
                setAltKey(pointMenu, "altkey.menu.point");
-               _editPointItem = new JMenuItem(I18nManager.getText("menu.edit.editpoint"));
+               _editPointItem = new JMenuItem(I18nManager.getText("menu.point.editpoint"));
                _editPointAction = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -406,7 +411,7 @@ public class MenuManager implements DataSubscriber
                _editWaypointNameItem = makeMenuItem(FunctionLibrary.FUNCTION_EDIT_WAYPOINT_NAME);
                _editWaypointNameItem.setEnabled(false);
                pointMenu.add(_editWaypointNameItem);
-               _deletePointItem = new JMenuItem(I18nManager.getText("menu.edit.deletepoint"));
+               _deletePointItem = new JMenuItem(I18nManager.getText("menu.point.deletepoint"));
                _deletePointAction = new ActionListener() {
                        public void actionPerformed(ActionEvent e)
                        {
@@ -415,6 +420,7 @@ public class MenuManager implements DataSubscriber
                };
                _deletePointItem.addActionListener(_deletePointAction);
                _deletePointItem.setEnabled(false);
+               _deletePointItem.setAccelerator(KeyStroke.getKeyStroke(KeyEvent.VK_DELETE, 0));
                pointMenu.add(_deletePointItem);
                pointMenu.addSeparator();
                // find a waypoint
@@ -576,22 +582,29 @@ public class MenuManager implements DataSubscriber
                // Set the map background
                JMenuItem mapBgItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_MAP_BG);
                settingsMenu.add(mapBgItem);
+               _onlineCheckbox = new JCheckBoxMenuItem(I18nManager.getText("menu.settings.onlinemode"));
+               _onlineCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_ONLINE_MODE));
+               _onlineCheckbox.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e) {
+                               boolean isOnline = _onlineCheckbox.isSelected();
+                               Config.setConfigBoolean(Config.KEY_ONLINE_MODE, isOnline);
+                               if (isOnline) {UpdateMessageBroker.informSubscribers();}
+                       }
+               });
+               settingsMenu.add(_onlineCheckbox);
+               settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_DISK_CACHE));
+               settingsMenu.addSeparator();
                // Set kmz image size
-               JMenuItem setKmzImageSizeItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_KMZ_IMAGE_SIZE);
-               settingsMenu.add(setKmzImageSizeItem);
+               settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_KMZ_IMAGE_SIZE));
                // Set program paths
-               JMenuItem setPathsItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_PATHS);
-               settingsMenu.add(setPathsItem);
+               settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_PATHS));
                // Set colours
-               JMenuItem setColoursItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS);
-               settingsMenu.add(setColoursItem);
+               settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_COLOURS));
                // Set language
-               JMenuItem setLanguageItem = makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE);
-               settingsMenu.add(setLanguageItem);
+               settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_LANGUAGE));
                settingsMenu.addSeparator();
                // Save configuration
-               JMenuItem saveConfigMenuItem = makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG);
-               settingsMenu.add(saveConfigMenuItem);
+               settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG));
                menubar.add(settingsMenu);
 
                // Help menu
@@ -600,12 +613,9 @@ public class MenuManager implements DataSubscriber
                JMenuItem helpItem = makeMenuItem(FunctionLibrary.FUNCTION_HELP);
                setShortcut(helpItem, "shortcut.menu.help.help");
                helpMenu.add(helpItem);
-               JMenuItem showKeysItem = makeMenuItem(FunctionLibrary.FUNCTION_SHOW_KEYS);
-               helpMenu.add(showKeysItem);
-               JMenuItem aboutItem = makeMenuItem(FunctionLibrary.FUNCTION_ABOUT);
-               helpMenu.add(aboutItem);
-               JMenuItem checkVersionItem = makeMenuItem(FunctionLibrary.FUNCTION_CHECK_VERSION);
-               helpMenu.add(checkVersionItem);
+               helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SHOW_KEYS));
+               helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_ABOUT));
+               helpMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_CHECK_VERSION));
                menubar.add(helpMenu);
 
                return menubar;
@@ -658,7 +668,9 @@ public class MenuManager implements DataSubscriber
                        if (code >= 0 && code < 26)
                        {
                                // Found a valid code between A and Z
-                               inMenuItem.setAccelerator(KeyStroke.getKeyStroke(KEY_EVENTS[code], InputEvent.CTRL_DOWN_MASK));
+                               inMenuItem.setAccelerator(KeyStroke.getKeyStroke(KEY_EVENTS[code],
+                                       Toolkit.getDefaultToolkit().getMenuShortcutKeyMask()));
+                               // use platform-specific key mask so Ctrl on Linux/Win, Clover on Mac
                        }
                }
        }
@@ -672,7 +684,7 @@ public class MenuManager implements DataSubscriber
                JToolBar toolbar = new JToolBar();
                // Add text file
                JButton openFileButton = new JButton(IconManager.getImageIcon(IconManager.OPEN_FILE));
-               openFileButton.setToolTipText(I18nManager.getText("menu.file.open"));
+               openFileButton.setToolTipText(I18nManager.getText("function.open"));
                openFileButton.addActionListener(_openFileAction);
                toolbar.add(openFileButton);
                // Add photo
@@ -688,36 +700,36 @@ public class MenuManager implements DataSubscriber
                toolbar.add(_saveButton);
                // Undo
                _undoButton = new JButton(IconManager.getImageIcon(IconManager.UNDO));
-               _undoButton.setToolTipText(I18nManager.getText("menu.edit.undo"));
+               _undoButton.setToolTipText(I18nManager.getText("menu.track.undo"));
                _undoButton.addActionListener(_undoAction);
                _undoButton.setEnabled(false);
                toolbar.add(_undoButton);
                // Edit point
                _editPointButton = new JButton(IconManager.getImageIcon(IconManager.EDIT_POINT));
-               _editPointButton.setToolTipText(I18nManager.getText("menu.edit.editpoint"));
+               _editPointButton.setToolTipText(I18nManager.getText("menu.point.editpoint"));
                _editPointButton.addActionListener(_editPointAction);
                _editPointButton.setEnabled(false);
                toolbar.add(_editPointButton);
                // Delete point
                _deletePointButton = new JButton(IconManager.getImageIcon(IconManager.DELETE_POINT));
-               _deletePointButton.setToolTipText(I18nManager.getText("menu.edit.deletepoint"));
+               _deletePointButton.setToolTipText(I18nManager.getText("menu.point.deletepoint"));
                _deletePointButton.addActionListener(_deletePointAction);
                _deletePointButton.setEnabled(false);
                toolbar.add(_deletePointButton);
                // Delete range
                _deleteRangeButton = new JButton(IconManager.getImageIcon(IconManager.DELETE_RANGE));
-               _deleteRangeButton.setToolTipText(I18nManager.getText("menu.edit.deleterange"));
+               _deleteRangeButton.setToolTipText(I18nManager.getText("menu.range.deleterange"));
                _deleteRangeButton.addActionListener(_deleteRangeAction);
                _deleteRangeButton.setEnabled(false);
                toolbar.add(_deleteRangeButton);
                // Select start, end
                _selectStartButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_START));
-               _selectStartButton.setToolTipText(I18nManager.getText("menu.select.start"));
+               _selectStartButton.setToolTipText(I18nManager.getText("menu.range.start"));
                _selectStartButton.addActionListener(_selectStartAction);
                _selectStartButton.setEnabled(false);
                toolbar.add(_selectStartButton);
                _selectEndButton = new JButton(IconManager.getImageIcon(IconManager.SET_RANGE_END));
-               _selectEndButton.setToolTipText(I18nManager.getText("menu.select.end"));
+               _selectEndButton.setToolTipText(I18nManager.getText("menu.range.end"));
                _selectEndButton.addActionListener(_selectEndAction);
                _selectEndButton.setEnabled(false);
                toolbar.add(_selectEndButton);
@@ -769,6 +781,7 @@ public class MenuManager implements DataSubscriber
                _browserMapMenu.setEnabled(hasData);
                _distanceItem.setEnabled(hasData);
                _getGpsiesItem.setEnabled(hasData);
+               _lookupSrtmItem.setEnabled(hasData);
                _findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
                // is undo available?
                boolean hasUndo = !_app.getUndoStack().isEmpty();
index 101f1a39c64aefcada6069c146765d4938ce3f34..88e77ca58ce6795986185604435eb59e317a6b8e 100644 (file)
@@ -19,6 +19,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
        private Photo _photo = null;
        private BufferedImage _thumbnail = null;
        private boolean _loadingImage = false;
+       private boolean _loadFailed = false;
        /** String to show before photo is loaded */
        private static final String LOADING_STRING = I18nManager.getText("details.photo.loading") + " ...";
 
@@ -42,6 +43,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
                if (_photo != inPhoto) {
                        _photo = inPhoto;
                        _thumbnail = null;
+                       _loadFailed = false;
                }
                repaint();
        }
@@ -51,6 +53,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
         */
        public void refresh() {
                _thumbnail = null;
+               _loadFailed = false;
        }
 
        /**
@@ -63,7 +66,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
                if (_photo != null)
                {
                        // read thumbnail in separate thread
-                       if (_thumbnail == null && !_loadingImage)
+                       if (_thumbnail == null && !_loadingImage && !_loadFailed)
                        {
                                _loadingImage = true;
                                new Thread(this).start();
@@ -74,7 +77,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
                                inG.setColor(Color.BLACK);
                                inG.drawString(LOADING_STRING, 10, 30);
                        }
-                       else
+                       else if (_thumbnail != null && !_loadFailed)
                        {
                                // Copy scaled, smoothed (and rotated) image into scaled
                                int usableWidth = getParent().getWidth()-10;
@@ -124,6 +127,7 @@ public class PhotoThumbnail extends JPanel implements Runnable
                                _thumbnail = ImageUtils.createScaledImage(image, thumbSize.width, thumbSize.height);
                                image = null;
                        }
+                       else _loadFailed = true;
                }
                _loadingImage = false;
                repaint();
diff --git a/tim/prune/gui/ProfileChart.java b/tim/prune/gui/ProfileChart.java
deleted file mode 100644 (file)
index 7c7b4c5..0000000
+++ /dev/null
@@ -1,242 +0,0 @@
-package tim.prune.gui;
-
-import java.awt.Color;
-import java.awt.Dimension;
-import java.awt.Graphics;
-import java.awt.event.MouseEvent;
-
-import tim.prune.I18nManager;
-import tim.prune.config.ColourScheme;
-import tim.prune.config.Config;
-import tim.prune.data.Altitude;
-import tim.prune.data.AltitudeRange;
-import tim.prune.data.Track;
-import tim.prune.data.TrackInfo;
-
-/**
- * Chart component for the profile display
- */
-public class ProfileChart extends GenericChart
-{
-       /** Current scale factor in x direction*/
-       private double _xScaleFactor = 0.0;
-       /** Possible altitude scales to use */
-       private static final int[] ALTITUDE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50};
-
-
-       /**
-        * Constructor
-        * @param inTrackInfo Track info object
-        */
-       public ProfileChart(TrackInfo inTrackInfo)
-       {
-               super(inTrackInfo);
-               MINIMUM_SIZE = new Dimension(200, 100);
-               addMouseListener(this);
-       }
-
-
-       /**
-        * Override paint method to draw map
-        * @param g Graphics object
-        */
-       public void paint(Graphics g)
-       {
-               super.paint(g);
-               if (_track != null && _track.getNumPoints() > 0)
-               {
-                       int width = getWidth();
-                       int height = getHeight();
-
-                       // Set up colours
-                       final Color barColour = Config.getColourScheme().getColour(ColourScheme.IDX_POINT);
-                       final Color rangeColour = Config.getColourScheme().getColour(ColourScheme.IDX_SELECTION);
-                       final Color currentColour = Config.getColourScheme().getColour(ColourScheme.IDX_PRIMARY);
-                       final Color secondColour = Config.getColourScheme().getColour(ColourScheme.IDX_SECONDARY);
-                       final Color lineColour = Config.getColourScheme().getColour(ColourScheme.IDX_LINES);
-
-                       // message if no altitudes in track
-                       if (!_track.hasAltitudeData())
-                       {
-                               g.setColor(lineColour);
-                               g.drawString(I18nManager.getText("display.noaltitudes"), 50, height/2);
-                               return;
-                       }
-
-                       // altitude profile
-                       AltitudeRange altitudeRange = _track.getAltitudeRange();
-                       int minAltitude = altitudeRange.getMinimum();
-                       int maxAltitude = altitudeRange.getMaximum();
-                       int numPoints = _track.getNumPoints();
-                       _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH - 1) / numPoints;
-                       double yScaleFactor = 1.0 * (height - 2 * BORDER_WIDTH) / (maxAltitude - minAltitude);
-                       int barWidth = (int) (_xScaleFactor + 1.0);
-                       int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
-                       // selection start, end
-                       int selectionStart = -1, selectionEnd = -1;
-                       if (_trackInfo.getSelection().hasRangeSelected()) {
-                               selectionStart = _trackInfo.getSelection().getStart();
-                               selectionEnd = _trackInfo.getSelection().getEnd();
-                       }
-
-                       // horizontal lines for scale - set to round numbers eg 500m
-                       int lineScale = getLineScale(minAltitude, maxAltitude);
-                       int altitude = 0;
-                       int x = 0, y = 0;
-                       if (lineScale > 1)
-                       {
-                               g.setColor(lineColour);
-                               while (altitude < maxAltitude)
-                               {
-                                       if (altitude > minAltitude)
-                                       {
-                                               y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
-                                               g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
-                                       }
-                                       altitude += lineScale;
-                               }
-                       }
-
-                       try
-                       {
-                               // loop through points
-                               Altitude.Format chartFormat = altitudeRange.getFormat();
-                               g.setColor(barColour);
-                               for (int p = 0; p < numPoints; p++)
-                               {
-                                       x = (int) (_xScaleFactor * p) + 1;
-                                       if (p == selectionStart)
-                                               g.setColor(rangeColour);
-                                       else if (p == (selectionEnd+1))
-                                               g.setColor(barColour);
-                                       if (_track.getPoint(p).getAltitude().isValid())
-                                       {
-                                               altitude = _track.getPoint(p).getAltitude().getValue(chartFormat);
-                                               y = (int) (yScaleFactor * (altitude - minAltitude));
-                                               g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
-                                       }
-                               }
-                               // current point (make sure it's drawn last)
-                               if (selectedPoint > -1)
-                               {
-                                       Altitude alt = _track.getPoint(selectedPoint).getAltitude();
-                                       if (alt.isValid())
-                                       {
-                                               x = (int) (_xScaleFactor * selectedPoint) + 1;
-                                               g.setColor(secondColour);
-                                               g.fillRect(BORDER_WIDTH + x, BORDER_WIDTH+1, barWidth, height-2*BORDER_WIDTH-2);
-                                               g.setColor(currentColour);
-                                               altitude = alt.getValue(chartFormat);
-                                               y = (int) (yScaleFactor * (altitude - minAltitude));
-                                               g.fillRect(BORDER_WIDTH + x, height-BORDER_WIDTH - y, barWidth, y);
-                                       }
-                               }
-                       }
-                       catch (NullPointerException npe) { // ignore, probably due to data being changed
-                       }
-                       // Draw numbers on top of the graph to mark scale
-                       if (lineScale > 1)
-                       {
-                               int textHeight = g.getFontMetrics().getHeight();
-                               altitude = 0;
-                               y = 0;
-                               g.setColor(currentColour);
-                               while (altitude < maxAltitude)
-                               {
-                                       if (altitude > minAltitude)
-                                       {
-                                               y = height - BORDER_WIDTH - (int) (yScaleFactor * (altitude - minAltitude));
-                                               // Limit y so String isn't above border
-                                               if (y < (BORDER_WIDTH + textHeight))
-                                               {
-                                                       y = BORDER_WIDTH + textHeight;
-                                               }
-                                               g.drawString(""+altitude, BORDER_WIDTH + 5, y);
-                                       }
-                                       altitude += lineScale;
-                               }
-                       }
-               }
-       }
-
-
-       /**
-        * Work out the scale for the horizontal lines
-        * @param inMin min altitude of data
-        * @param inMax max altitude of data
-        * @return scale separation, or -1 for no scale
-        */
-       private int getLineScale(int inMin, int inMax)
-       {
-               if ((inMax - inMin) < 50 || inMax < 0)
-               {
-                       return -1;
-               }
-               int numScales = ALTITUDE_SCALES.length;
-               int scale = 0;
-               int numLines = 0;
-               int altitude = 0;
-               for (int i=0; i<numScales; i++)
-               {
-                       scale = ALTITUDE_SCALES[i];
-                       if (scale < inMax)
-                       {
-                               numLines = 0;
-                               altitude = 0;
-                               while (altitude < inMax)
-                               {
-                                       altitude += scale;
-                                       if (altitude > inMin)
-                                       {
-                                               numLines++;
-                                       }
-                               }
-                               if (numLines > 2)
-                               {
-                                       return scale;
-                               }
-                       }
-               }
-               // no suitable scale found so just use minimum
-               return ALTITUDE_SCALES[numScales-1];
-       }
-
-
-       /**
-        * Method to inform map that data has changed
-        * @param inTrack track object
-        */
-       public void dataUpdated(Track inTrack)
-       {
-               _track = inTrack;
-               repaint();
-       }
-
-
-       /**
-        * React to click on profile display
-        */
-       public void mouseClicked(MouseEvent e)
-       {
-               // ignore right clicks
-               if (_track != null && !e.isMetaDown())
-               {
-                       int xClick = e.getX();
-                       int yClick = e.getY();
-                       // Check click is within main area (not in border)
-                       if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
-                               && yClick < (getHeight() - BORDER_WIDTH))
-                       {
-                               // work out which data point is nearest and select it
-                               int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
-                               // If shift clicked, then extend selection
-                               if (e.isShiftDown()) {
-                                       _trackInfo.extendSelection(pointNum);
-                               }
-                               else {
-                                       _trackInfo.selectPoint(pointNum);
-                               }
-                       }
-               }
-       }
-}
diff --git a/tim/prune/gui/map/CloudmadeMapSource.java b/tim/prune/gui/map/CloudmadeMapSource.java
new file mode 100644 (file)
index 0000000..0cc9b77
--- /dev/null
@@ -0,0 +1,53 @@
+package tim.prune.gui.map;
+
+/**
+ * Class to act as a source for Cloudmade maps with a given style
+ */
+public class CloudmadeMapSource extends OsmMapSource
+{
+       /** Selected style number */
+       private String _style = null;
+       /** Server prefix including API-key unique to Prune application */
+       private static final String SERVER_PREFIX = "tile.cloudmade.com/03d86b66f51f4a3b8c236ac06f2a2e57/";
+
+       /**
+        * Constructor
+        * @param inName name to use for map source
+        * @param inStyle style, given as integer
+        * @param inMaxZoom maximum zoom level, 18 by default
+        */
+       public CloudmadeMapSource(String inName, String inStyle, int inMaxZoom)
+       {
+               // Note: Could check style for valid integer value here
+               super(inName, SERVER_PREFIX + inStyle + "/256/", null, inMaxZoom);
+               _style = inStyle;
+       }
+
+       /**
+        * @return semicolon-separated list of all fields
+        */
+       public String getConfigString()
+       {
+               return "c:" +  getName() + ";" + _style + ";" + getMaxZoomLevel();
+       }
+
+       /**
+        * Construct a new map source from its config string
+        * @param inConfigString string from Config, separated by semicolons
+        * @return new map source, or null if not parseable
+        */
+       public static CloudmadeMapSource fromConfig(String inConfigString)
+       {
+               CloudmadeMapSource source = null;
+               if (inConfigString.startsWith("c:"))
+               {
+                       String[] items = inConfigString.substring(2).split(";");
+                       try {
+                               if (items.length == 3) {
+                                       source = new CloudmadeMapSource(items[0], items[1], Integer.parseInt(items[2]));
+                               }
+                       } catch (NumberFormatException nfe) {}
+               }
+               return source;
+       }
+}
diff --git a/tim/prune/gui/map/DiskTileCacher.java b/tim/prune/gui/map/DiskTileCacher.java
new file mode 100644 (file)
index 0000000..dfc4f92
--- /dev/null
@@ -0,0 +1,151 @@
+package tim.prune.gui.map;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.ImageObserver;
+import java.io.File;
+import java.io.FileOutputStream;
+import java.io.IOException;
+import java.io.InputStream;
+import java.net.URL;
+
+/**
+ * Class to control the reading and saving of map tiles
+ * to a cache on disk
+ */
+public class DiskTileCacher implements Runnable
+{
+       /** URL to get image from */
+       private URL _url = null;
+       /** File to save image to */
+       private File _file = null;
+       /** Observer to be notified */
+       private ImageObserver _observer = null;
+       /** Time limit to cache images for */
+       private static final long CACHE_TIME_LIMIT = 20 * 24 * 60 * 60 * 1000; // 20 days in ms
+
+       /**
+        * Private constructor
+        * @param inUrl URL to get
+        * @param inFile file to save to
+        */
+       private DiskTileCacher(URL inUrl, File inFile, ImageObserver inObserver)
+       {
+               _url = inUrl;
+               _file = inFile;
+               _observer = inObserver;
+               new Thread(this).start();
+       }
+
+       /**
+        * Get the specified tile from the disk cache
+        * @param inBasePath base path to whole disk cache
+        * @param inTilePath relative path to requested tile
+        * @param inCheckAge true to check age of file, false to ignore
+        * @return tile image if available, or null if not there
+        */
+       public static Image getTile(String inBasePath, String inTilePath, boolean inCheckAge)
+       {
+               if (inBasePath == null) {return null;}
+               File tileFile = new File(inBasePath, inTilePath);
+               Image image = null;
+               if (tileFile.exists() && tileFile.canRead() && tileFile.length() > 0) {
+                       long fileStamp = tileFile.lastModified();
+                       if (!inCheckAge || ((System.currentTimeMillis()-fileStamp) < CACHE_TIME_LIMIT))
+                       {
+                               try {
+                                       image = Toolkit.getDefaultToolkit().createImage(tileFile.getAbsolutePath());
+                               }
+                               catch (Exception e) {}
+                       }
+               }
+               return image;
+       }
+
+       /**
+        * Save the specified image tile to disk
+        * @param inUrl url to get image from
+        * @param inBasePath base path to disk cache
+        * @param inTilePath relative path to this tile
+        * @param inObserver observer to inform when load complete
+        */
+       public static void saveTile(URL inUrl, String inBasePath, String inTilePath, ImageObserver inObserver)
+       {
+               if (inBasePath == null || inTilePath == null) {return;}
+               // save file if possible
+               File basePath = new File(inBasePath);
+               if (!basePath.exists() || !basePath.isDirectory() || !basePath.canWrite()) {
+                       //System.err.println("Can't write");
+                       // Can't write to base path
+                       return;
+               }
+               File tileFile = new File(basePath, inTilePath);
+               // Check if this file is already being loaded
+               if (!isBeingLoaded(tileFile))
+               {
+                       File dir = tileFile.getParentFile();
+                       // Start a new thread to load the image if necessary
+                       if (dir.exists() || dir.mkdirs())
+                       {
+                               new DiskTileCacher(inUrl, tileFile, inObserver);
+                       }
+               }
+       }
+
+       /**
+        * Check whether the given tile is already being loaded
+        * @param inFile desired file
+        * @return true if temporary file with this name exists
+        */
+       private static boolean isBeingLoaded(File inFile)
+       {
+               File tempFile = new File(inFile.getAbsolutePath() + ".temp");
+               return tempFile.exists();
+       }
+
+       /**
+        * Run method for loading URL asynchronously and saving to file
+        */
+       public void run()
+       {
+               boolean finished = false;
+               InputStream in = null;
+               FileOutputStream out = null;
+               File tempFile = new File(_file.getAbsolutePath() + ".temp");
+               // Use a synchronized block across all threads to make sure this url is only fetched once
+               synchronized (DiskTileCacher.class) {
+                       if (tempFile.exists()) {return;}
+                       try {
+                               if (!tempFile.createNewFile()) {return;}
+                       }
+                       catch (Exception e) {return;}
+               }
+               try {
+                       // Open streams from URL and to file
+                       out = new FileOutputStream(tempFile);
+                       in = _url.openStream();
+                       int d = 0;
+                       // Loop over each byte in the stream (maybe buffering is more efficient?)
+                       while ((d = in.read()) >= 0) {
+                               out.write(d);
+                       }
+                       finished = true;
+               } catch (IOException e) {}
+               finally {
+                       try {
+                               in.close();
+                               out.close();
+                               if (!finished) {tempFile.delete();}
+                       }
+                       catch (Exception e) {} // ignore
+               }
+               // Move temp file to desired file location
+               if (!tempFile.renameTo(_file)) {
+                       // File couldn't be moved - delete both to be sure
+                       tempFile.delete();
+                       _file.delete();
+               }
+               // Tell parent that load is finished (parameters ignored)
+               _observer.imageUpdate(null, ImageObserver.ALLBITS, 0, 0, 0, 0);
+       }
+}
index d2f36ce165b45cfd5c315da68c6a70b5726a1f51..2717fcb66952417dc90189a95b49e75a963bc437 100644 (file)
@@ -40,6 +40,7 @@ import tim.prune.I18nManager;
 import tim.prune.UpdateMessageBroker;
 import tim.prune.config.ColourScheme;
 import tim.prune.config.Config;
+import tim.prune.data.Checker;
 import tim.prune.data.Coordinate;
 import tim.prune.data.DataPoint;
 import tim.prune.data.DoubleRange;
@@ -66,8 +67,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
        private Selection _selection = null;
        /** Previously selected point */
        private int _prevSelectedPoint = -1;
-       /** Tile cacher */
-       private MapTileCacher _tileCacher = new MapTileCacher(this);
+       /** Tile manager */
+       private MapTileManager _tileManager = new MapTileManager(this);
        /** Image to display */
        private BufferedImage _mapImage = null;
        /** Slider for transparency */
@@ -153,7 +154,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                ItemListener mapCheckListener = new ItemListener() {
                        public void itemStateChanged(ItemEvent e)
                        {
-                               _tileCacher.clearAll();
+                               _tileManager.clearMemoryCaches();
                                _recalculate = true;
                                Config.setConfigBoolean(Config.KEY_SHOW_MAP, e.getStateChange() == ItemEvent.SELECTED);
                                UpdateMessageBroker.informSubscribers(); // to let menu know
@@ -372,10 +373,10 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                _prevSelectedPoint = selectedPoint;
                        }
 
-                       // Draw the mapImage if necessary
+                       // Draw the map contents if necessary
                        if ((_mapImage == null || _recalculate))
                        {
-                               getMapTiles();
+                               paintMapContents();
                                _scaleBar.updateScale(_mapPosition.getZoom(), _mapPosition.getCentreTileY());
                        }
                        // Draw the prepared image onto the panel
@@ -406,9 +407,9 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 
 
        /**
-        * Get the map tiles for the current zoom level and given tile parameters
+        * Paint the map tiles and the points on to the _mapImage
         */
-       private void getMapTiles()
+       private void paintMapContents()
        {
                if (_mapImage == null || _mapImage.getWidth() != getWidth() || _mapImage.getHeight() != getHeight())
                {
@@ -427,16 +428,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
 
                // reset error message
                if (!showMap) {_shownOsmErrorAlready = false;}
+               _recalculate = false;
                // Only get map tiles if selected
                if (showMap)
                {
                        // init tile cacher
-                       _tileCacher.centreMap(_mapPosition.getZoom(), _mapPosition.getCentreTileX(), _mapPosition.getCentreTileY());
+                       _tileManager.centreMap(_mapPosition.getZoom(), _mapPosition.getCentreTileX(), _mapPosition.getCentreTileY());
 
                        boolean loadingFailed = false;
                        if (_mapImage == null) return;
 
-                       if (_tileCacher.isOverzoomed())
+                       if (_tileManager.isOverzoomed())
                        {
                                // display overzoom message
                                g.setColor(COLOR_MESSAGES);
@@ -444,6 +446,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        }
                        else
                        {
+                               int numLayers = _tileManager.getNumLayers();
                                // Loop over tiles drawing each one
                                int[] tileIndices = _mapPosition.getTileIndices(getWidth(), getHeight());
                                int[] pixelOffsets = _mapPosition.getDisplayOffsets(getWidth(), getHeight());
@@ -453,9 +456,13 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                        for (int tileY = tileIndices[2]; tileY <= tileIndices[3]; tileY++)
                                        {
                                                int y = (tileY - tileIndices[2]) * 256 - pixelOffsets[1];
-                                               Image image = _tileCacher.getTile(tileX, tileY);
-                                               if (image != null) {
-                                                       g.drawImage(image, x, y, 256, 256, null);
+                                               // Loop over layers
+                                               for (int l=0; l<numLayers; l++)
+                                               {
+                                                       Image image = _tileManager.getTile(l, tileX, tileY);
+                                                       if (image != null) {
+                                                               g.drawImage(image, x, y, 256, 256, null);
+                                                       }
                                                }
                                        }
                                }
@@ -485,7 +492,6 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                // free g
                g.dispose();
 
-               _recalculate = false;
                // Zoom to fit if no points found
                if (pointsPainted <= 0 && _checkBounds) {
                        zoomToFit();
@@ -919,7 +925,7 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        _checkBounds = true;
                }
                if ((inUpdateType & DataSubscriber.MAPSERVER_CHANGED) > 0) {
-                       _tileCacher.setTileConfig(new MapTileConfig());
+                       _tileManager.resetConfig();
                }
                repaint();
                // enable or disable components
@@ -938,8 +944,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
        {
                int code = inE.getKeyCode();
                int currPointIndex = _selection.getCurrentPointIndex();
-               // Check for meta key
-               if (inE.isControlDown())
+               // Check for Ctrl key (for Linux/Win) or meta key (Clover key for Mac)
+               if (inE.isControlDown() || inE.isMetaDown())
                {
                        // Check for arrow keys to zoom in and out
                        if (code == KeyEvent.VK_UP)
@@ -951,6 +957,17 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                                _trackInfo.selectPoint(currPointIndex-1);
                        else if (code == KeyEvent.VK_RIGHT)
                                _trackInfo.selectPoint(currPointIndex+1);
+                       else if (code == KeyEvent.VK_PAGE_UP)
+                               _trackInfo.selectPoint(Checker.getPreviousSegmentStart(
+                                       _trackInfo.getTrack(), _trackInfo.getSelection().getCurrentPointIndex()));
+                       else if (code == KeyEvent.VK_PAGE_DOWN)
+                               _trackInfo.selectPoint(Checker.getNextSegmentStart(
+                                       _trackInfo.getTrack(), _trackInfo.getSelection().getCurrentPointIndex()));
+                       // Check for home and end
+                       else if (code == KeyEvent.VK_HOME)
+                               _trackInfo.selectPoint(0);
+                       else if (code == KeyEvent.VK_END)
+                               _trackInfo.selectPoint(_trackInfo.getTrack().getNumPoints()-1);
                }
                else
                {
@@ -966,9 +983,8 @@ public class MapCanvas extends JPanel implements MouseListener, MouseMotionListe
                        else if (code == KeyEvent.VK_LEFT)
                                rightwardsPan = -PAN_DISTANCE;
                        panMap(rightwardsPan, upwardsPan);
-                       // Check for delete key to delete current point
-                       if (code == KeyEvent.VK_DELETE && currPointIndex >= 0)
-                       {
+                       // Check for backspace key to delete current point (delete key already handled by menu)
+                       if (code == KeyEvent.VK_BACK_SPACE && currPointIndex >= 0) {
                                _app.deleteCurrentPoint();
                        }
                }
diff --git a/tim/prune/gui/map/MapSource.java b/tim/prune/gui/map/MapSource.java
new file mode 100644 (file)
index 0000000..c2311ae
--- /dev/null
@@ -0,0 +1,124 @@
+package tim.prune.gui.map;
+
+import java.net.MalformedURLException;
+import java.net.URL;
+
+/**
+ * Class to represent any map source, whether an OsmMapSource
+ * or one of the more complicated ones.
+ * Map sources may contain just one or several layers, and may
+ * build their URLs in different ways depending on the source
+ */
+public abstract class MapSource
+{
+       /**
+        * @return the number of layers used in this source
+        */
+       public abstract int getNumLayers();
+
+       /**
+        * @return the name of the source
+        */
+       public abstract String getName();
+
+       /**
+        * @return the base url for the specified layer
+        */
+       public abstract String getBaseUrl(int inLayerNum);
+
+       /**
+        * @return the site name for the specified layer
+        */
+       public abstract String getSiteName(int inLayerNum);
+
+       /**
+        * @return the file extension for the specified layer
+        */
+       public abstract String getFileExtension(int inLayerNum);
+
+       /**
+        * Make the URL to get the specified tile
+        * @param inLayerNum number of layer, from 0 (base) to getNumLayers-1 (top)
+        * @param inZoom zoom level
+        * @param inX x coordinate of tile
+        * @param inY y coordinate of tile
+        * @return URL as string
+        */
+       public abstract String makeURL(int inLayerNum, int inZoom, int inX, int inY);
+
+       /**
+        * @return the maximum zoom level for this source
+        */
+       public abstract int getMaxZoomLevel();
+
+       /**
+        * Make a relative file path from the base directory including site name
+        * @param inLayerNum layer number
+        * @param inZoom zoom level
+        * @param inX x coordinate
+        * @param inY y coordinate
+        * @return relative file path as String
+        */
+       public String makeFilePath(int inLayerNum, int inZoom, int inX, int inY)
+       {
+               return getSiteName(inLayerNum) + inZoom + "/" + inX + "/" + inY + getFileExtension(inLayerNum);
+       }
+
+       /**
+        * Checks the given url for having the right prefix and trailing slash
+        * @param inUrl url to check
+        * @return validated url with correct prefix and trailing slash, or null
+        */
+       protected static String fixBaseUrl(String inUrl)
+       {
+               if (inUrl == null || inUrl.equals("")) {return null;}
+               String url = inUrl;
+               // check prefix
+               try {
+                       new URL(url);
+               }
+               catch (MalformedURLException e) {
+                       // add the http protocol
+                       url = "http://" + url;
+               }
+               // check trailing /
+               if (!url.endsWith("/")) {
+                       url = url + "/";
+               }
+               return url;
+       }
+
+       /**
+        * Fix the site name by stripping off protocol and www.
+        * This is used to create the file path for disk caching
+        * @param inUrl url to strip
+        * @return stripped url
+        */
+       protected static String fixSiteName(String inUrl)
+       {
+               if (inUrl == null || inUrl.equals("")) {return null;}
+               String url = inUrl.toLowerCase();
+               int idx = url.indexOf("://");
+               if (idx >= 0) {url = url.substring(idx + 3);}
+               if (url.startsWith("www.")) {url = url.substring(4);}
+               return url;
+       }
+
+       /**
+        * @return string which can be written to the Config
+        */
+       public abstract String getConfigString();
+
+       /**
+        * @return semicolon-separated list of base urls in order
+        */
+       public String getSiteStrings()
+       {
+               String s = "";
+               for (int i=0; i<getNumLayers(); i++) {
+                       String url = getBaseUrl(i);
+                       if (url != null) {s = s + url + ";";}
+               }
+               return s;
+       }
+}
diff --git a/tim/prune/gui/map/MapSourceLibrary.java b/tim/prune/gui/map/MapSourceLibrary.java
new file mode 100644 (file)
index 0000000..df30219
--- /dev/null
@@ -0,0 +1,141 @@
+package tim.prune.gui.map;
+
+import java.util.ArrayList;
+
+import tim.prune.config.Config;
+
+/**
+ * Class to hold a library for all the map sources
+ * and provide access to each one
+ */
+public abstract class MapSourceLibrary
+{
+       /** list of map sources */
+       private static ArrayList<MapSource> _sourceList = null;
+       /** Number of fixed sources */
+       private static int _numFixedSources = 0;
+
+       // Static block to initialise source list
+       static
+       {
+               _sourceList = new ArrayList<MapSource>();
+               addFixedSources();
+               _numFixedSources = _sourceList.size();
+               addConfigSources();
+       }
+
+       /** Private constructor to block instantiation */
+       private MapSourceLibrary() {}
+
+
+       /** @return number of fixed sources which shouldn't be deleted */
+       public static int getNumFixedSources() {
+               return _numFixedSources;
+       }
+
+       /**
+        * Initialise source list by adding bare minimum
+        */
+       private static void addFixedSources()
+       {
+               _sourceList.add(new OsmMapSource("Mapnik", "http://tile.openstreetmap.org/"));
+               _sourceList.add(new OsmMapSource("Osma", "http://tah.openstreetmap.org/Tiles/tile/"));
+               _sourceList.add(new OsmMapSource("Cyclemap", "http://andy.sandbox.cloudmade.com/tiles/cycle/"));
+               _sourceList.add(new OsmMapSource("Reitkarte", "http://topo.geofabrik.de/hills/",
+                       "http://topo.openstreetmap.de/topo/", 18));
+               _sourceList.add(new MffMapSource("Mapsforfree", "http://maps-for-free.com/layer/relief/", ".jpg",
+                       "http://maps-for-free.com/layer/water/", ".gif", 11));
+               _sourceList.add(new CloudmadeMapSource("Pale Dawn", "998", 18));
+       }
+
+       /**
+        * Add custom sources from Config to the library
+        */
+       private static void addConfigSources()
+       {
+               String configString = Config.getConfigString(Config.KEY_MAPSOURCE_LIST);
+               if (configString != null && configString.length() > 10)
+               {
+                       // Loop over sources in string, separated by vertical bars
+                       int splitPos = configString.indexOf('|');
+                       while (splitPos > 0)
+                       {
+                               String sourceString = configString.substring(0, splitPos);
+                               MapSource source = OsmMapSource.fromConfig(sourceString);
+                               if (source == null) {source = CloudmadeMapSource.fromConfig(sourceString);}
+                               if (source != null) {
+                                       _sourceList.add(source);
+                               }
+                               configString = configString.substring(splitPos+1);
+                               splitPos = configString.indexOf('|');
+                       }
+               }
+       }
+
+       /**
+        * @return current number of sources
+        */
+       public static int getNumSources() {
+               return _sourceList.size();
+       }
+
+       /**
+        * Add the given MapSource to the list (at the end)
+        * @param inSource MapSource object
+        */
+       public static void addSource(MapSource inSource) {
+               // Check whether source is already there?  Check whether valid?
+               _sourceList.add(inSource);
+       }
+
+       /**
+        * @param inIndex source index number
+        * @return corresponding map source object
+        */
+       public static MapSource getSource(int inIndex)
+       {
+               // Check whether within range
+               if (inIndex < 0 || inIndex >= _sourceList.size()) {return null;}
+               return _sourceList.get(inIndex);
+       }
+
+       /**
+        * Delete the specified source
+        * @param inIndex index of source to delete
+        */
+       public static void deleteSource(int inIndex)
+       {
+               if (inIndex >= _numFixedSources) {
+                       _sourceList.remove(inIndex);
+               }
+       }
+
+       /**
+        * Check whether the given name already exists in the library (case-insensitive)
+        * @param inName name to check
+        * @return true if already exists, false otherwise
+        */
+       public static boolean hasSourceName(String inName)
+       {
+               if (inName == null) {return false;}
+               String checkName = inName.toLowerCase().trim();
+               for (int i=0; i<getNumSources(); i++)
+               {
+                       String name = getSource(i).getName().toLowerCase();
+                       if (name.equals(checkName)) {return true;}
+               }
+               return false;
+       }
+
+       /**
+        * @return String containing all custom-added sources as a |-separated list
+        */
+       public static String getConfigString()
+       {
+               StringBuilder builder = new StringBuilder();
+               for (int i=getNumFixedSources(); i<getNumSources(); i++) {
+                       builder.append(getSource(i).getConfigString()).append('|');
+               }
+               return builder.toString();
+       }
+}
diff --git a/tim/prune/gui/map/MapTileCacher.java b/tim/prune/gui/map/MapTileCacher.java
deleted file mode 100644 (file)
index 366e1ad..0000000
+++ /dev/null
@@ -1,226 +0,0 @@
-package tim.prune.gui.map;
-
-import java.awt.Image;
-import java.awt.Toolkit;
-import java.awt.image.ImageObserver;
-import java.net.MalformedURLException;
-import java.net.URL;
-
-
-/**
- * Class to handle the caching of map tiles from openstreetmap
- */
-public class MapTileCacher implements ImageObserver
-{
-       /** Parent to be informed of updates */
-       private MapCanvas _parent = null;
-       /** Array of images to hold tiles */
-       private Image[] _tiles = new Image[GRID_SIZE * GRID_SIZE];
-       /** Current zoom level */
-       private int _zoom = -1;
-       /** X coordinate of central tile */
-       private int _tileX = -1;
-       /** Y coordinate of central tile */
-       private int _tileY = -1;
-       /** X coord of grid centre */
-       private int _gridCentreX = 0;
-       /** Y coord of grid centre */
-       private int _gridCentreY = 0;
-       /** Tile configuration */
-       private MapTileConfig _tileConfig = null;
-
-       /** Grid size */
-       private static final int GRID_SIZE = 15;
-       /** max zoom level of map tiles */
-       private static final int MAX_TILE_ZOOM = 18;
-
-
-       /**
-        * Constructor
-        * @param inParent parent canvas to be informed of updates
-        */
-       public MapTileCacher(MapCanvas inParent)
-       {
-               _parent = inParent;
-       }
-
-       /**
-        * Recentre the map and clear the cache
-        * @param inZoom zoom level
-        * @param inTileX x coord of central tile
-        * @param inTileY y coord of central tile
-        */
-       public void centreMap(int inZoom, int inTileX, int inTileY)
-       {
-               int shift = Math.max(Math.abs(inTileX-_tileX), Math.abs(inTileY - _tileY));
-               if (shift == 0) {return;}
-               // Clear cache if either zoom has changed or map has jumped too far
-               if (inZoom != _zoom || shift > GRID_SIZE/2)
-               {
-                       _zoom = inZoom;
-                       clearAll();
-               }
-               _gridCentreX = getCacheCoordinate(_gridCentreX + inTileX - _tileX);
-               _gridCentreY = getCacheCoordinate(_gridCentreY + inTileY - _tileY);
-               _tileX = inTileX;
-               _tileY = inTileY;
-               // Mark boundaries as invalid
-               for (int i=0; i<GRID_SIZE; i++)
-               {
-                       _tiles[getArrayIndex(_tileX + GRID_SIZE/2 + 1, _tileY + i - GRID_SIZE/2)] = null;
-                       _tiles[getArrayIndex(_tileX + i - GRID_SIZE/2, _tileY + GRID_SIZE/2 + 1)] = null;
-               }
-       }
-
-       /**
-        * Clear all the cached images
-        */
-       public void clearAll()
-       {
-               // Clear all images if zoom changed
-               for (int i=0; i<_tiles.length; i++) {
-                       _tiles[i] = null;
-               }
-       }
-
-       /**
-        * @param inX x index of tile
-        * @param inY y index of tile
-        * @return selected tile if already loaded, or null otherwise
-        */
-       public Image getTile(int inX, int inY)
-       {
-               if (_tileConfig == null) {_tileConfig = new MapTileConfig();}
-               int arrayIndex = getArrayIndex(inX, inY);
-               Image image = _tiles[arrayIndex];
-               if (image != null)
-               {
-                       // image already finished loading so return it
-                       return image;
-               }
-
-               // Protect against zoom > max
-               if (isOverzoomed()) return null;
-
-               // Trigger load if not already triggered
-               // Work out tile coords for URL
-               int urlX = getUrlCoordinate(inX, _zoom);
-               int urlY = getUrlCoordinate(inY, _zoom);
-               try
-               {
-                       // Use configured tile server
-                       String url = _tileConfig.getUrl() + _zoom + "/" + urlX + "/" + urlY + ".png";
-                       // Load image asynchronously, using observer
-                       image = Toolkit.getDefaultToolkit().createImage(new URL(url));
-                       _tiles[arrayIndex] = image;
-                       if (image.getWidth(this) > 0) {return image;}
-               }
-               catch (MalformedURLException urle) {} // ignore
-               return null;
-       }
-
-       /**
-        * @return true if zoom is too high for tiles
-        */
-       public boolean isOverzoomed()
-       {
-               return (_zoom > MAX_TILE_ZOOM);
-       }
-
-       /**
-        * Get the array index for the given coordinates
-        * @param inX x coord of tile
-        * @param inY y coord of tile
-        * @return array index
-        */
-       private int getArrayIndex(int inX, int inY)
-       {
-               //System.out.println("Getting array index for (" + inX + ", " + inY + ") where the centre is at ("  + _tileX + ", " + _tileY
-               //      + ") and grid coords (" + _gridCentreX + ", " + _gridCentreY + ")");
-               int x = getCacheCoordinate(inX - _tileX + _gridCentreX);
-               int y = getCacheCoordinate(inY - _tileY + _gridCentreY);
-               //System.out.println("Transformed to (" + x + ", " + y + ")");
-               return (x + y * GRID_SIZE);
-       }
-
-       /**
-        * Transform a coordinate from map tiles to array coordinates
-        * @param inTile coordinate of tile
-        * @return coordinate in array (wrapping around cache grid)
-        */
-       private static int getCacheCoordinate(int inTile)
-       {
-               int tile = inTile;
-               while (tile >= GRID_SIZE) {tile -= GRID_SIZE;}
-               while (tile < 0) {tile += GRID_SIZE;}
-               return tile;
-       }
-
-       /**
-        * Make sure a url coordinate is within range
-        * @param inTile coordinate of tile in map system
-        * @param inZoom zoom factor
-        * @return coordinate for url (either vertical or horizontal)
-        */
-       private static int getUrlCoordinate(int inTile, int inZoom)
-       {
-               int mapSize = 1 << inZoom;
-               int coord = inTile;
-               while (coord >= mapSize) {coord -= mapSize;}
-               while (coord < 0) {coord += mapSize;}
-               // coord is now between 0 and mapsize
-               return coord;
-       }
-
-       /**
-        * Convert to string for debug
-        * @see java.lang.Object#toString()
-        */
-       public String toString()
-       {
-               StringBuffer result = new StringBuffer("Grid centre (" + _gridCentreX + "," + _gridCentreY + ") - (" + _tileX + "," + _tileY + ")\n");
-               for (int i=0; i<GRID_SIZE; i++)
-               {
-                       for (int j=0; j<GRID_SIZE; j++) {
-                               if (i == _gridCentreY && j == _gridCentreX) {
-                                       result.append(_tiles[j + i*GRID_SIZE] == null?"c":"C");
-                               }
-                               else {
-                                       result.append(_tiles[j + i*GRID_SIZE] == null?".":"*");
-                               }
-                       }
-                       result.append("\n");
-               }
-               return result.toString();
-       }
-
-       /**
-        * Method called by image loader to inform of updates to the tiles
-        * @param img the image
-        * @param infoflags flags describing how much of the image is known
-        * @param x ignored
-        * @param y ignored
-        * @param width ignored
-        * @param height ignored
-        * @return false to carry on loading, true to stop
-        */
-       public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
-       {
-               boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
-               boolean error = (infoflags & ImageObserver.ERROR) > 0;
-               if (loaded || error) {
-                       _parent.tilesUpdated(loaded);
-               }
-               return !loaded;
-       }
-
-       /**
-        * Set or reset the tile config
-        * @param inConfig object containing tile config
-        */
-       public void setTileConfig(MapTileConfig inConfig)
-       {
-               _tileConfig = inConfig;
-               clearAll();
-       }
-}
diff --git a/tim/prune/gui/map/MapTileConfig.java b/tim/prune/gui/map/MapTileConfig.java
deleted file mode 100644 (file)
index e545125..0000000
+++ /dev/null
@@ -1,92 +0,0 @@
-package tim.prune.gui.map;
-
-import java.net.MalformedURLException;
-import java.net.URL;
-
-import tim.prune.config.Config;
-
-/**
- * Class to hold the config for the map tiles
- * and retrieve the correct URL prefix
- */
-public class MapTileConfig
-{
-       /** Index of map server */
-       private int _index = 0;
-       /** Url for other */
-       private String _url = null;
-
-       /** server urls for known maps */
-       private static final String[] SERVER_URLS = {
-               "http://tile.openstreetmap.org/", // mapnik
-               "http://tah.openstreetmap.org/Tiles/tile/",      // osma
-               "http://andy.sandbox.cloudmade.com/tiles/cycle/" // cyclemap
-       };
-       /** Index of 'other' server with freeform url */
-       private static final int OTHER_SERVER_NUM = 3;
-
-
-       /**
-        * Default constructor using Config
-        */
-       public MapTileConfig()
-       {
-               _index = Config.getConfigInt(Config.KEY_MAPSERVERINDEX);
-               _url = fixUrl(Config.getConfigString(Config.KEY_MAPSERVERURL));
-               // reset index wrong or if other url too short
-               if (_index < 0 || _index > OTHER_SERVER_NUM ||
-                       (_index == OTHER_SERVER_NUM && (_url == null || _url.length() < 5)))
-               {
-                       _index = 0;
-               }
-       }
-
-       /**
-        * @return url
-        */
-       public String getUrl()
-       {
-               if (_index == OTHER_SERVER_NUM) {return _url;}
-               return SERVER_URLS[_index];
-       }
-
-       /**
-        * Checks the given url for having the right prefix and trailing slash
-        * @param inUrl url to check
-        * @return validated url with correct prefix and trailing slash, or null
-        */
-       private static String fixUrl(String inUrl)
-       {
-               if (inUrl == null || inUrl.equals("")) {return null;}
-               String url = inUrl;
-               // check prefix
-               try {
-                       new URL(url);
-               }
-               catch (MalformedURLException e) {
-                       // add the http protocol
-                       url = "http://" + url;
-               }
-               // check trailing /
-               if (!url.endsWith("/")) {
-                       url = url + "/";
-               }
-               return url;
-       }
-
-       /**
-        * @param inOther other config object
-        * @return true if the objects are exactly the same
-        */
-       public boolean equals(MapTileConfig inOther)
-       {
-               // Other object must be non-null and must have same index
-               if (inOther == null || inOther._index != _index) {return false;}
-               // Check url if other selected
-               if (_index == OTHER_SERVER_NUM) {
-                       return inOther._url.equals(_url);
-               }
-               // Not other so must match
-               return true;
-       }
-}
diff --git a/tim/prune/gui/map/MapTileManager.java b/tim/prune/gui/map/MapTileManager.java
new file mode 100644 (file)
index 0000000..9f1fbfe
--- /dev/null
@@ -0,0 +1,178 @@
+package tim.prune.gui.map;
+
+import java.awt.Image;
+import java.awt.Toolkit;
+import java.awt.image.ImageObserver;
+import java.net.MalformedURLException;
+import java.net.URL;
+
+import tim.prune.config.Config;
+
+/**
+ * Class responsible for managing the map tiles,
+ * including invoking the correct memory cacher(s) and/or disk cacher(s)
+ */
+public class MapTileManager implements ImageObserver
+{
+       /** Parent object to inform when tiles received */
+       private MapCanvas _parent = null;
+       /** Current map source */
+       private MapSource _mapSource = null;
+       /** Array of tile caches, one per layer */
+       private MemTileCacher[] _tempCaches = null;
+       /** Number of layers */
+       private int _numLayers = -1;
+       /** Current zoom level */
+       private int _zoom = 0;
+
+
+       /**
+        * Constructor
+        * @param inParent parent canvas to be informed of updates
+        */
+       public MapTileManager(MapCanvas inParent)
+       {
+               _parent = inParent;
+               resetConfig();
+       }
+
+       /**
+        * Recentre the map
+        * @param inZoom zoom level
+        * @param inTileX x coord of central tile
+        * @param inTileY y coord of central tile
+        */
+       public void centreMap(int inZoom, int inTileX, int inTileY)
+       {
+               _zoom = inZoom;
+               // Pass params onto all memory cachers
+               if (_tempCaches != null) {
+                       for (int i=0; i<_tempCaches.length; i++) {
+                               _tempCaches[i].centreMap(inZoom, inTileX, inTileY);
+                       }
+               }
+       }
+
+       /**
+        * @return true if zoom is too high for tiles
+        */
+       public boolean isOverzoomed()
+       {
+               // Ask current map source what maximum zoom is
+               int maxZoom = (_mapSource == null?0:_mapSource.getMaxZoomLevel());
+               return (_zoom > maxZoom);
+       }
+
+       /**
+        * Clear all the memory caches due to changed config / zoom
+        */
+       public void clearMemoryCaches()
+       {
+               int numLayers = _mapSource.getNumLayers();
+               if (_tempCaches == null || _tempCaches.length != numLayers) {
+                       // Ccahers don't match, so need to create the right number of them
+                       _tempCaches = new MemTileCacher[numLayers];
+                       for (int i=0; i<numLayers; i++) {
+                               _tempCaches[i] = new MemTileCacher();
+                       }
+               }
+               else {
+                       // Cachers already there, just need to be cleared
+                       for (int i=0; i<numLayers; i++) {
+                               _tempCaches[i].clearAll();
+                       }
+               }
+       }
+
+       /**
+        * Reset the map source configuration, apparently it has changed
+        */
+       public void resetConfig()
+       {
+               int sourceNum = Config.getConfigInt(Config.KEY_MAPSOURCE_INDEX);
+               _mapSource = MapSourceLibrary.getSource(sourceNum);
+               if (_mapSource == null) {_mapSource = MapSourceLibrary.getSource(0);}
+               clearMemoryCaches();
+               _numLayers = _mapSource.getNumLayers();
+       }
+
+       /**
+        * @return the number of layers in the map
+        */
+       public int getNumLayers()
+       {
+               return _numLayers;
+       }
+
+       /**
+        * @param inLayer layer number, starting from 0
+        * @param inX x index of tile
+        * @param inY y index of tile
+        * @return selected tile if already loaded, or null otherwise
+        */
+       public Image getTile(int inLayer, int inX, int inY)
+       {
+               // Check first in memory cache for tile
+               MemTileCacher tempCache = _tempCaches[inLayer]; // Should probably guard against nulls and array indexes here
+               Image tile = tempCache.getTile(inX, inY);
+               if (tile != null) {
+                       return tile;
+               }
+
+               // Tile wasn't in memory, but maybe it's in disk cache (if there is one)
+               String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
+               boolean useDisk = (diskCachePath != null);
+               boolean onlineMode = Config.getConfigBoolean(Config.KEY_ONLINE_MODE);
+               if (useDisk)
+               {
+                       tile = DiskTileCacher.getTile(diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), onlineMode);
+                       if (tile != null) {
+                               // Pass tile to memory cache
+                               tempCache.setTile(tile, inX, inY);
+                               if (tile.getWidth(this) > 0) {return tile;}
+                               return null;
+                       }
+               }
+               // Tile wasn't in memory or on disk, so if online let's get it
+               if (onlineMode)
+               {
+                       try
+                       {
+                               URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
+                               if (useDisk) {
+                                       // Copy image directly from URL stream to disk cache
+                                       DiskTileCacher.saveTile(tileUrl, diskCachePath, _mapSource.makeFilePath(inLayer, _zoom, inX, inY), this);
+                               }
+                               else {
+                                       // Load image asynchronously, using observer
+                                       tile = Toolkit.getDefaultToolkit().createImage(tileUrl);
+                                       // Pass to memory cache
+                                       _tempCaches[inLayer].setTile(tile, inX, inY);
+                                       if (tile.getWidth(this) > 0) {return tile;}
+                               }
+                       }
+                       catch (MalformedURLException urle) {} // ignore
+               }
+               return null;
+       }
+
+       /**
+        * Method called by image loader to inform of updates to the tiles
+        * @param img the image
+        * @param infoflags flags describing how much of the image is known
+        * @param x ignored
+        * @param y ignored
+        * @param width ignored
+        * @param height ignored
+        * @return false to carry on loading, true to stop
+        */
+       public boolean imageUpdate(Image img, int infoflags, int x, int y, int width, int height)
+       {
+               boolean loaded = (infoflags & ImageObserver.ALLBITS) > 0;
+               boolean error = (infoflags & ImageObserver.ERROR) > 0;
+               if (loaded || error) {
+                       _parent.tilesUpdated(loaded);
+               }
+               return !loaded;
+       }
+}
diff --git a/tim/prune/gui/map/MemTileCacher.java b/tim/prune/gui/map/MemTileCacher.java
new file mode 100644 (file)
index 0000000..69b5f83
--- /dev/null
@@ -0,0 +1,115 @@
+package tim.prune.gui.map;
+
+import java.awt.Image;
+
+/**
+ * Class to act as a memory-based map tile cache
+ * For caching of tiles on disk, see the DiskTileCacher class.
+ */
+public class MemTileCacher
+{
+       /** Array of images to hold tiles */
+       private Image[] _tiles = new Image[GRID_SIZE * GRID_SIZE];
+       /** Current zoom level */
+       private int _zoom = -1;
+       /** X coordinate of central tile */
+       private int _tileX = -1;
+       /** Y coordinate of central tile */
+       private int _tileY = -1;
+       /** X coord of grid centre */
+       private int _gridCentreX = 0;
+       /** Y coord of grid centre */
+       private int _gridCentreY = 0;
+
+       /** Grid size */
+       private static final int GRID_SIZE = 15;
+
+       /**
+        * Recentre the map and clear the cache
+        * @param inZoom zoom level
+        * @param inTileX x coord of central tile
+        * @param inTileY y coord of central tile
+        */
+       public void centreMap(int inZoom, int inTileX, int inTileY)
+       {
+               int shift = Math.max(Math.abs(inTileX-_tileX), Math.abs(inTileY - _tileY));
+               if (shift == 0) {return;}
+               // Clear cache if either zoom has changed or map has jumped too far
+               if (inZoom != _zoom || shift > GRID_SIZE/2)
+               {
+                       _zoom = inZoom;
+                       clearAll();
+               }
+               _gridCentreX = getCacheCoordinate(_gridCentreX + inTileX - _tileX);
+               _gridCentreY = getCacheCoordinate(_gridCentreY + inTileY - _tileY);
+               _tileX = inTileX;
+               _tileY = inTileY;
+               // Mark boundaries as invalid
+               for (int i=0; i<GRID_SIZE; i++)
+               {
+                       _tiles[getArrayIndex(_tileX + GRID_SIZE/2 + 1, _tileY + i - GRID_SIZE/2)] = null;
+                       _tiles[getArrayIndex(_tileX + i - GRID_SIZE/2, _tileY + GRID_SIZE/2 + 1)] = null;
+               }
+       }
+
+       /**
+        * Transform a coordinate from map tiles to array coordinates
+        * @param inTile coordinate of tile
+        * @return coordinate in array (wrapping around cache grid)
+        */
+       private static int getCacheCoordinate(int inTile)
+       {
+               int tile = inTile;
+               while (tile >= GRID_SIZE) {tile -= GRID_SIZE;}
+               while (tile < 0) {tile += GRID_SIZE;}
+               return tile;
+       }
+
+       /**
+        * Get the array index for the given coordinates
+        * @param inX x coord of tile
+        * @param inY y coord of tile
+        * @return array index
+        */
+       private int getArrayIndex(int inX, int inY)
+       {
+               //System.out.println("Getting array index for (" + inX + ", " + inY + ") where the centre is at ("  + _tileX + ", " + _tileY
+               //      + ") and grid coords (" + _gridCentreX + ", " + _gridCentreY + ")");
+               int x = getCacheCoordinate(inX - _tileX + _gridCentreX);
+               int y = getCacheCoordinate(inY - _tileY + _gridCentreY);
+               //System.out.println("Transformed to (" + x + ", " + y + ")");
+               return (x + y * GRID_SIZE);
+       }
+
+       /**
+        * Clear all the cached images
+        */
+       public void clearAll()
+       {
+               // Clear all images if zoom changed
+               for (int i=0; i<_tiles.length; i++) {
+                       _tiles[i] = null;
+               }
+       }
+
+       /**
+        * @param inX x index of tile
+        * @param inY y index of tile
+        * @return selected tile if already loaded, or null otherwise
+        */
+       public Image getTile(int inX, int inY)
+       {
+               return _tiles[getArrayIndex(inX, inY)];
+       }
+
+       /**
+        * Save the specified tile at the given coordinates
+        * @param inTile image to save
+        * @param inX x coordinate of tile
+        * @param inY y coordinate of tile
+        */
+       public void setTile(Image inTile, int inX, int inY)
+       {
+               _tiles[getArrayIndex(inX, inY)] = inTile;
+       }
+}
diff --git a/tim/prune/gui/map/MffMapSource.java b/tim/prune/gui/map/MffMapSource.java
new file mode 100644 (file)
index 0000000..772d8e9
--- /dev/null
@@ -0,0 +1,96 @@
+package tim.prune.gui.map;
+
+import tim.prune.I18nManager;
+
+/**
+ * Class to provide a map source for maps-for-free sources
+ * These are double-layer sources with jpg and gif tiles
+ */
+public class MffMapSource extends MapSource
+{
+       /** Name for this source */
+       private String _name = null;
+       /** Base urls */
+       private String[] _baseUrls = null;
+       /** Site names */
+       private String[] _siteNames = null;
+       /** File extensions */
+       private String[] _extensions = null;
+       /** Maximum zoom level */
+       private int _maxZoom = 0;
+
+       /**
+        * Constructor giving name, url and maximum zoom
+        * @param inName source name
+        * @param inUrl base url
+        * @param inMaxZoom maximum zoom level
+        */
+       public MffMapSource(String inName, String inUrl1, String inExt1,
+               String inUrl2, String inExt2, int inMaxZoom)
+       {
+               _name = inName;
+               if (_name == null || _name.trim().equals("")) {_name = I18nManager.getText("mapsource.unknown");}
+               _baseUrls = new String[2];
+               _baseUrls[0] = fixBaseUrl(inUrl1);
+               _baseUrls[1] = fixBaseUrl(inUrl2);
+               _siteNames = new String[2];
+               _siteNames[0] = fixSiteName(_baseUrls[0]);
+               _siteNames[1] = fixSiteName(_baseUrls[1]);
+               _extensions = new String[2];
+               _extensions[0] = inExt1;
+               _extensions[1] = inExt2;
+               _maxZoom = inMaxZoom;
+       }
+
+       /**
+        * @return name
+        */
+       public String getName() {
+               return _name;
+       }
+
+       /** Number of layers is always 2 for mff sources */
+       public int getNumLayers() {
+               return 2;
+       }
+
+       /** Get base url for specified layer */
+       public String getBaseUrl(int inLayerNum) {
+               return _baseUrls[inLayerNum];
+       }
+
+       /** site name without protocol or www. */
+       public String getSiteName(int inLayerNum) {
+               return _siteNames[inLayerNum];
+       }
+
+       /**
+        * Make the URL to get the specified tile
+        */
+       public String makeURL(int inLayerNum, int inZoom, int inX, int inY)
+       {
+               return _baseUrls[inLayerNum] + "z" + inZoom + "/row" + inY + "/" + inZoom + "_" + inX + "-" + inY + getFileExtension(inLayerNum);
+       }
+
+       /** Get right file extension for this layer */
+       public final String getFileExtension(int inLayerNum) {
+               return _extensions[inLayerNum];
+       }
+
+       /**
+        * @return maximum zoom level
+        */
+       public final int getMaxZoomLevel()
+       {
+               return _maxZoom;
+       }
+
+       /**
+        * @return semicolon-separated list of all fields
+        */
+       public String getConfigString()
+       {
+               // TODO: Maybe a gui will be necessary for this one day
+               return "not required";
+       }
+}
diff --git a/tim/prune/gui/map/OsmMapSource.java b/tim/prune/gui/map/OsmMapSource.java
new file mode 100644 (file)
index 0000000..7686307
--- /dev/null
@@ -0,0 +1,132 @@
+package tim.prune.gui.map;
+
+import tim.prune.I18nManager;
+
+/**
+ * Class to provide a map source for all OSM-like sources
+ * (eg mapnik, opencyclemap, openpistemap etc).
+ * These can be single-layer or double-layer sources with png tiles
+ */
+public class OsmMapSource extends MapSource
+{
+       /** Name for this source */
+       private String _name = null;
+       /** Base urls */
+       private String[] _baseUrls = null;
+       /** Site names */
+       private String[] _siteNames = null;
+       /** Maximum zoom level */
+       private int _maxZoom = 0;
+
+       /**
+        * Constructor giving single name and url
+        * @param inName source name
+        * @param inUrl base url
+        */
+       public OsmMapSource(String inName, String inUrl)
+       {
+               this(inName, inUrl, null, 18);
+       }
+
+       /**
+        * Constructor giving name, urls and maximum zoom
+        * @param inName source name
+        * @param inUrl1 base layer url
+        * @param inUrl2 upper layer url
+        * @param inMaxZoom maximum zoom level
+        */
+       public OsmMapSource(String inName, String inUrl1, String inUrl2, int inMaxZoom)
+       {
+               _name = inName;
+               if (_name == null || _name.trim().equals("")) {_name = I18nManager.getText("mapsource.unknown");}
+               _baseUrls = new String[2];
+               _baseUrls[0] = fixBaseUrl(inUrl1);
+               _baseUrls[1] = fixBaseUrl(inUrl2);
+               _siteNames = new String[2];
+               _siteNames[0] = fixSiteName(_baseUrls[0]);
+               _siteNames[1] = fixSiteName(_baseUrls[1]);
+               // Swap layers if second layer given without first
+               if (_baseUrls[0] == null && _baseUrls[1] != null)
+               {
+                       _baseUrls[0] = _baseUrls[1];
+                       _siteNames[0] = _siteNames[1];
+                       _baseUrls[1] = _siteNames[1] = null;
+               }
+               _maxZoom = inMaxZoom;
+       }
+
+       /**
+        * Construct a new map source from its config string
+        * @param inConfigString string from Config, separated by semicolons
+        * @return new map source, or null if not parseable
+        */
+       public static OsmMapSource fromConfig(String inConfigString)
+       {
+               OsmMapSource source = null;
+               if (inConfigString.startsWith("o:"))
+               {
+                       String[] items = inConfigString.substring(2).split(";");
+                       try {
+                               if (items.length == 3) {
+                                       source = new OsmMapSource(items[0], items[1], null, Integer.parseInt(items[2]));
+                               }
+                               else if (items.length == 4) {
+                                       source = new OsmMapSource(items[0], items[1], items[2], Integer.parseInt(items[3]));
+                               }
+                       } catch (NumberFormatException nfe) {}
+               }
+               return source;
+       }
+
+       /**
+        * @return name
+        */
+       public String getName() {
+               return _name;
+       }
+
+       /** Number of layers */
+       public int getNumLayers() {
+               return _baseUrls[1] == null?1:2;
+       }
+
+       /** Base url for this source */
+       public String getBaseUrl(int inLayerNum) {
+               return _baseUrls[inLayerNum];
+       }
+
+       /** site name without protocol or www. */
+       public String getSiteName(int inLayerNum) {
+               return _siteNames[inLayerNum];
+       }
+
+       /**
+        * Make the URL to get the specified tile
+        */
+       public String makeURL(int inLayerNum, int inZoom, int inX, int inY)
+       {
+               return _baseUrls[inLayerNum] + inZoom + "/" + inX + "/" + inY + getFileExtension(inLayerNum);
+       }
+
+       /** file extension is always png */
+       public final String getFileExtension(int inLayerNum) {
+               return ".png";
+       }
+
+       /**
+        * @return maximum zoom level
+        */
+       public final int getMaxZoomLevel()
+       {
+               return _maxZoom;
+       }
+
+
+       /**
+        * @return semicolon-separated list of all fields
+        */
+       public String getConfigString()
+       {
+               return "o:" +  getName() + ";" + getSiteStrings() + getMaxZoomLevel();
+       }
+}
diff --git a/tim/prune/gui/profile/AltitudeData.java b/tim/prune/gui/profile/AltitudeData.java
new file mode 100644 (file)
index 0000000..90130cc
--- /dev/null
@@ -0,0 +1,74 @@
+package tim.prune.gui.profile;
+
+import tim.prune.I18nManager;
+import tim.prune.data.Altitude;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Track;
+
+/**
+ * Class to provide a source of altitude data for the profile chart
+ */
+public class AltitudeData extends ProfileData
+{
+       /** Altitude format for values */
+       private Altitude.Format _altitudeFormat = Altitude.Format.NO_FORMAT;
+
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        */
+       public AltitudeData(Track inTrack) {
+               super(inTrack);
+       }
+
+       /**
+        * Get the data and populate the instance arrays
+        */
+       public void init()
+       {
+               initArrays();
+               _hasData = false;
+               _altitudeFormat = Altitude.Format.NO_FORMAT;
+               if (_track != null) {
+                       for (int i=0; i<_track.getNumPoints(); i++)
+                       {
+                               DataPoint point = _track.getPoint(i);
+                               if (point != null && point.hasAltitude())
+                               {
+                                       // Point has an altitude - if it's the first one, use its format
+                                       if (_altitudeFormat == Altitude.Format.NO_FORMAT)
+                                       {
+                                               _altitudeFormat = point.getAltitude().getFormat();
+                                               _minValue = _maxValue = point.getAltitude().getValue();
+                                       }
+                                       // Store the value and maintain max and min values
+                                       double value = point.getAltitude().getValue(_altitudeFormat);
+                                       _pointValues[i] = value;
+                                       if (value < _minValue) {_minValue = value;}
+                                       if (value > _maxValue) {_maxValue = value;}
+
+                                       _hasData = true;
+                                       _pointHasData[i] = true;
+                               }
+                       }
+               }
+       }
+
+       /**
+        * @return text description including units
+        */
+       public String getLabel()
+       {
+               return I18nManager.getText("fieldname.altitude") + " ("
+                       + I18nManager.getText(_altitudeFormat==Altitude.Format.FEET?"units.feet.short":"units.metres.short")
+                       + ")";
+       }
+
+       /**
+        * @return key for message when no altitudes present
+        */
+       public String getNoDataKey() {
+               return "display.noaltitudes";
+       }
+}
diff --git a/tim/prune/gui/profile/ProfileChart.java b/tim/prune/gui/profile/ProfileChart.java
new file mode 100644 (file)
index 0000000..d989ebf
--- /dev/null
@@ -0,0 +1,351 @@
+package tim.prune.gui.profile;
+
+import java.awt.Color;
+import java.awt.Dimension;
+import java.awt.FlowLayout;
+import java.awt.Graphics;
+import java.awt.event.ActionEvent;
+import java.awt.event.ActionListener;
+import java.awt.event.MouseEvent;
+import java.awt.event.MouseListener;
+import javax.swing.JLabel;
+import javax.swing.JMenuItem;
+import javax.swing.JPopupMenu;
+
+import tim.prune.I18nManager;
+import tim.prune.config.ColourScheme;
+import tim.prune.config.Config;
+import tim.prune.data.TrackInfo;
+import tim.prune.gui.GenericDisplay;
+
+/**
+ * Chart component for the profile display
+ */
+public class ProfileChart extends GenericDisplay implements MouseListener
+{
+       /** Current scale factor in x direction*/
+       private double _xScaleFactor = 0.0;
+       /** Data to show on chart */
+       private ProfileData _data = null;
+       /** Label for chart type, units */
+       private JLabel _label = null;
+       /** Right-click popup menu */
+       private JPopupMenu _popup = null;
+
+       /** Possible scales to use */
+       private static final int[] LINE_SCALES = {10000, 5000, 2000, 1000, 500, 200, 100, 50, 10, 5};
+       /** Border width around black line */
+       private static final int BORDER_WIDTH = 6;
+       /** Minimum size for profile chart in pixels */
+       private static final Dimension MINIMUM_SIZE = new Dimension(200, 110);
+       /** Colour to use for text if no data found */
+       private static final Color COLOR_NODATA_TEXT = Color.GRAY;
+       /** Chart type */
+       private static enum ChartType {ALTITUDE, SPEED};
+
+
+       /**
+        * Constructor
+        * @param inTrackInfo Track info object
+        */
+       public ProfileChart(TrackInfo inTrackInfo)
+       {
+               super(inTrackInfo);
+               _data = new AltitudeData(inTrackInfo.getTrack());
+               addMouseListener(this);
+               setLayout(new FlowLayout(FlowLayout.LEFT));
+               _label = new JLabel("Altitude");
+               add(_label);
+               makePopup();
+       }
+
+
+       /**
+        * Override minimum size method to restrict slider
+        */
+       public Dimension getMinimumSize()
+       {
+               return MINIMUM_SIZE;
+       }
+
+       /**
+        * Override paint method to draw map
+        * @param g Graphics object
+        */
+       public void paint(Graphics g)
+       {
+               super.paint(g);
+               ColourScheme colourScheme = Config.getColourScheme();
+               paintBackground(g, colourScheme);
+               if (_track != null && _track.getNumPoints() > 0)
+               {
+                       _data.init();
+                       _label.setText(_data.getLabel());
+                       int width = getWidth();
+                       int height = getHeight();
+
+                       // Set up colours
+                       final Color barColour = colourScheme.getColour(ColourScheme.IDX_POINT);
+                       final Color rangeColour = colourScheme.getColour(ColourScheme.IDX_SELECTION);
+                       final Color currentColour = colourScheme.getColour(ColourScheme.IDX_PRIMARY);
+                       final Color secondColour = colourScheme.getColour(ColourScheme.IDX_SECONDARY);
+                       final Color lineColour = colourScheme.getColour(ColourScheme.IDX_LINES);
+
+                       // message if no data for the current field in track
+                       if (!_data.hasData())
+                       {
+                               g.setColor(lineColour);
+                               g.drawString(I18nManager.getText(_data.getNoDataKey()), 50, (height+_label.getHeight())/2);
+                               paintChildren(g);
+                               return;
+                       }
+
+                       // Find minimum and maximum values to plot
+                       double minValue = _data.getMinValue();
+                       double maxValue = _data.getMaxValue();
+                       if (maxValue <= minValue) {maxValue = minValue + 1;}
+
+                       final int numPoints = _track.getNumPoints();
+                       _xScaleFactor = 1.0 * (width - 2 * BORDER_WIDTH - 1) / numPoints;
+                       int usableHeight = height - 2 * BORDER_WIDTH - _label.getHeight();
+                       double yScaleFactor = 1.0 * usableHeight / (maxValue - minValue);
+                       int barWidth = (int) (_xScaleFactor + 1.0);
+                       int selectedPoint = _trackInfo.getSelection().getCurrentPointIndex();
+                       // selection start, end
+                       int selectionStart = -1, selectionEnd = -1;
+                       if (_trackInfo.getSelection().hasRangeSelected()) {
+                               selectionStart = _trackInfo.getSelection().getStart();
+                               selectionEnd = _trackInfo.getSelection().getEnd();
+                       }
+
+                       // horizontal lines for scale - set to round numbers eg 500
+                       int lineScale = getLineScale(minValue, maxValue);
+                       int scaleValue = (int) (minValue/lineScale + 1) * lineScale;
+                       int x = 0, y = 0;
+                       double value = 0.0;
+                       if (lineScale > 1)
+                       {
+                               g.setColor(lineColour);
+                               while (scaleValue < maxValue)
+                               {
+                                       y = height - BORDER_WIDTH - (int) (yScaleFactor * (scaleValue - minValue));
+                                       g.drawLine(BORDER_WIDTH + 1, y, width - BORDER_WIDTH - 1, y);
+                                       scaleValue += lineScale;
+                               }
+                       }
+
+                       try
+                       {
+                               // loop through points
+                               g.setColor(barColour);
+                               for (int p = 0; p < numPoints; p++)
+                               {
+                                       x = (int) (_xScaleFactor * p) + 1;
+                                       if (p == selectionStart)
+                                               g.setColor(rangeColour);
+                                       else if (p == (selectionEnd+1))
+                                               g.setColor(barColour);
+                                       if (_data.hasData(p))
+                                       {
+                                               value = _data.getData(p);
+                                               y = (int) (yScaleFactor * (value - minValue));
+                                               g.fillRect(BORDER_WIDTH+x, height-BORDER_WIDTH - y, barWidth, y);
+                                       }
+                               }
+                               // current point (make sure it's drawn last)
+                               if (_data.hasData(selectedPoint))
+                               {
+                                       x = (int) (_xScaleFactor * selectedPoint) + 1;
+                                       g.setColor(secondColour);
+                                       g.fillRect(BORDER_WIDTH + x, height-usableHeight-BORDER_WIDTH+1, barWidth, usableHeight-2);
+                                       g.setColor(currentColour);
+                                       value = _data.getData(selectedPoint);
+                                       y = (int) (yScaleFactor * (value - minValue));
+                                       g.fillRect(BORDER_WIDTH + x, height-BORDER_WIDTH - y, barWidth, y);
+                               }
+                       }
+                       catch (NullPointerException npe) { // ignore, probably due to data being changed
+                       }
+                       // Draw numbers on top of the graph to mark scale
+                       if (lineScale > 1)
+                       {
+                               int textHeight = g.getFontMetrics().getHeight();
+                               scaleValue = (int) (minValue / lineScale + 1) * lineScale;
+                               y = 0;
+                               g.setColor(currentColour);
+                               while (scaleValue < maxValue)
+                               {
+                                       y = height - BORDER_WIDTH - (int) (yScaleFactor * (scaleValue - minValue));
+                                       // Limit y so String isn't above border
+                                       if (y < (BORDER_WIDTH + textHeight)) {
+                                               y = BORDER_WIDTH + textHeight;
+                                       }
+                                       g.drawString(""+scaleValue, BORDER_WIDTH + 5, y);
+                                       scaleValue += lineScale;
+                               }
+                       }
+                       // Paint label on top
+                       paintChildren(g);
+               }
+       }
+
+
+       /**
+        * Paint the background for the chart
+        * @param inG graphics object
+        * @param inColourScheme colour scheme
+        */
+       private void paintBackground(Graphics inG, ColourScheme inColourScheme)
+       {
+               final int width = getWidth();
+               final int height = getHeight();
+               // Get colours
+               final Color borderColour = inColourScheme.getColour(ColourScheme.IDX_BORDERS);
+               final Color backgroundColour = inColourScheme.getColour(ColourScheme.IDX_BACKGROUND);
+               // background
+               inG.setColor(backgroundColour);
+               inG.fillRect(0, 0, width, height);
+               if (width < 2*BORDER_WIDTH || height < 2*BORDER_WIDTH) return;
+               // Display message if no data to be displayed
+               if (_track == null || _track.getNumPoints() <= 0)
+               {
+                       inG.setColor(COLOR_NODATA_TEXT);
+                       inG.drawString(I18nManager.getText("display.nodata"), 50, height/2);
+               }
+               else {
+                       inG.setColor(borderColour);
+                       inG.drawRect(BORDER_WIDTH, BORDER_WIDTH + _label.getHeight(),
+                               width - 2*BORDER_WIDTH, height-2*BORDER_WIDTH-_label.getHeight());
+               }
+       }
+
+       /**
+        * Make the popup menu for right-clicking the chart
+        */
+       private void makePopup()
+       {
+               _popup = new JPopupMenu();
+               JMenuItem altItem = new JMenuItem(I18nManager.getText("fieldname.altitude"));
+               altItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               changeView(ChartType.ALTITUDE);
+                       }});
+               _popup.add(altItem);
+               JMenuItem speedItem = new JMenuItem(I18nManager.getText("fieldname.speed"));
+               speedItem.addActionListener(new ActionListener() {
+                       public void actionPerformed(ActionEvent e)
+                       {
+                               changeView(ChartType.SPEED);
+                       }});
+               _popup.add(speedItem);
+       }
+
+       /**
+        * Work out the scale for the horizontal lines
+        * @param inMin min value of data
+        * @param inMax max value of data
+        * @return scale separation, or -1 for no scale
+        */
+       private int getLineScale(double inMin, double inMax)
+       {
+               if ((inMax - inMin) < 5 || inMax < 0) {
+                       return -1;
+               }
+               int numScales = LINE_SCALES.length;
+               for (int i=0; i<numScales; i++)
+               {
+                       int scale = LINE_SCALES[i];
+                       int numLines = (int)(inMax / scale) - (int)(inMin / scale);
+                       // Check for too many lines
+                       if (numLines > 10) return -1;
+                       // If more than 1 line then use this scale
+                       if (numLines > 1) return scale;
+               }
+               // no suitable scale found so just use minimum
+               return LINE_SCALES[numScales-1];
+       }
+
+
+       /**
+        * Method to inform map that data has changed
+        */
+       public void dataUpdated(byte inUpdateType)
+       {
+               _data.init();
+               repaint();
+       }
+
+       /**
+        * React to click on profile display
+        */
+       public void mouseClicked(MouseEvent e)
+       {
+               if (_track == null || _track.getNumPoints() < 1) {return;}
+               // left clicks
+               if (!e.isMetaDown())
+               {
+                       int xClick = e.getX();
+                       int yClick = e.getY();
+                       // Check click is within main area (not in border)
+                       if (xClick > BORDER_WIDTH && yClick > BORDER_WIDTH && xClick < (getWidth() - BORDER_WIDTH)
+                               && yClick < (getHeight() - BORDER_WIDTH))
+                       {
+                               // work out which data point is nearest and select it
+                               int pointNum = (int) ((e.getX() - BORDER_WIDTH) / _xScaleFactor);
+                               // If shift clicked, then extend selection
+                               if (e.isShiftDown()) {
+                                       _trackInfo.extendSelection(pointNum);
+                               }
+                               else {
+                                       _trackInfo.selectPoint(pointNum);
+                               }
+                       }
+               }
+               else {
+                       // right clicks
+                       _popup.show(this, e.getX(), e.getY());
+               }
+       }
+
+       /**
+        * Called by clicking on popup menu to change the view
+        * @param inType selected chart type
+        */
+       private void changeView(ChartType inType)
+       {
+               if (inType == ChartType.ALTITUDE && !(_data instanceof AltitudeData))
+               {
+                       _data = new AltitudeData(_track);
+               }
+               else if (inType == ChartType.SPEED && !(_data instanceof SpeedData)) {
+                       _data = new SpeedData(_track);
+               }
+               _data.init();
+               repaint();
+       }
+
+       /**
+        * mouse enter events ignored
+        */
+       public void mouseEntered(MouseEvent e)
+       {}
+
+       /**
+        * mouse exit events ignored
+        */
+       public void mouseExited(MouseEvent e)
+       {}
+
+       /**
+        * ignore mouse pressed for now too
+        */
+       public void mousePressed(MouseEvent e)
+       {}
+
+       /**
+        * and also ignore mouse released
+        */
+       public void mouseReleased(MouseEvent e)
+       {}
+}
diff --git a/tim/prune/gui/profile/ProfileData.java b/tim/prune/gui/profile/ProfileData.java
new file mode 100644 (file)
index 0000000..8b036a9
--- /dev/null
@@ -0,0 +1,101 @@
+package tim.prune.gui.profile;
+
+import tim.prune.data.Track;
+
+/**
+ * Abstract class for all sources of profile data,
+ * including altitudes and speeds
+ */
+public abstract class ProfileData
+{
+       /** Track object */
+       protected final Track _track;
+       /** Flag for availability of any data */
+       protected boolean _hasData = false;
+       /** Array of booleans for data per point */
+       protected boolean[] _pointHasData = null;
+       /** Array of values per point */
+       protected double[] _pointValues = null;
+       /** Minimum value for track */
+       protected double _minValue = 0.0;
+       /** Maximum value for track */
+       protected double _maxValue = 0.0;
+
+       /**
+        * Constructor giving track object
+        * @param inTrack track object
+        */
+       public ProfileData(Track inTrack)
+       {
+               _track = inTrack;
+       }
+
+       /**
+        * @return true if this source has any data at all
+        */
+       public boolean hasData() {
+               return _hasData;
+       }
+
+       /**
+        * @param inPointNum index of point
+        * @return true if that point has data
+        */
+       public boolean hasData(int inPointNum)
+       {
+               return (_hasData && _pointHasData != null && inPointNum >= 0
+                       && inPointNum < _pointHasData.length && _pointHasData[inPointNum]);
+       }
+
+       /**
+        * @param inPointNum index of point
+        * @return value corresponding to that point
+        */
+       public double getData(int inPointNum)
+       {
+               if (!hasData(inPointNum)) {return 0.0;}
+               return _pointValues[inPointNum];
+       }
+
+       /**
+        * @return minimum value
+        */
+       public double getMinValue() {
+               return _minValue;
+       }
+
+       /**
+        * @return maximum value
+        */
+       public double getMaxValue() {
+               return _maxValue;
+       }
+
+       /**
+        * Get the data from the track and populate the value arrays
+        */
+       public abstract void init();
+
+       /**
+        * @return text for label including units
+        */
+       public abstract String getLabel();
+
+       /**
+        * @return key for message when no data available
+        */
+       public abstract String getNoDataKey();
+
+       /**
+        * Initialise the data arrays
+        */
+       protected void initArrays()
+       {
+               int numTrackPoints = _track.getNumPoints();
+               if (_pointHasData == null || _pointHasData.length != numTrackPoints)
+               {
+                       _pointHasData = new boolean[numTrackPoints];
+                       _pointValues = new double[numTrackPoints];
+               }
+       }
+}
diff --git a/tim/prune/gui/profile/SpeedData.java b/tim/prune/gui/profile/SpeedData.java
new file mode 100644 (file)
index 0000000..d836543
--- /dev/null
@@ -0,0 +1,83 @@
+package tim.prune.gui.profile;
+
+import tim.prune.I18nManager;
+import tim.prune.config.Config;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Distance;
+import tim.prune.data.Track;
+import tim.prune.data.Distance.Units;
+
+/**
+ * Class to provide a source of speed data for the profile chart
+ */
+public class SpeedData extends ProfileData
+{
+       /** Flag for metric units */
+       private boolean _metric = true;
+
+       /**
+        * Constructor
+        * @param inTrack track object
+        */
+       public SpeedData(Track inTrack) {
+               super(inTrack);
+       }
+
+       /**
+        * Get the data and populate the instance arrays
+        */
+       public void init()
+       {
+               initArrays();
+               _metric = Config.getConfigBoolean(Config.KEY_METRIC_UNITS);
+               _hasData = false;
+               _minValue = _maxValue = 0.0;
+               if (_track != null) {
+                       DataPoint prevPrevPoint = null, prevPoint = null, point = null;
+                       for (int i=0; i<_track.getNumPoints(); i++)
+                       {
+                               point = _track.getPoint(i);
+                               if (prevPrevPoint != null && prevPrevPoint.hasTimestamp()
+                                       && prevPoint != null && prevPoint.hasTimestamp()
+                                       && point != null && point.hasTimestamp())
+                               {
+                                       // All three points have timestamps
+                                       double seconds = point.getTimestamp().getSecondsSince(prevPrevPoint.getTimestamp());
+                                       if (seconds > 0)
+                                       {
+                                               double distInRads = DataPoint.calculateRadiansBetween(prevPrevPoint, prevPoint)
+                                                       + DataPoint.calculateRadiansBetween(prevPoint, point);
+                                               double dist = Distance.convertRadiansToDistance(distInRads, _metric?Units.KILOMETRES:Units.MILES);
+                                               // Store the value and maintain max and min values
+                                               double value = dist / seconds * 60.0 * 60.0;
+                                               _pointValues[i-1] = value;
+                                               if (value < _minValue || _minValue == 0.0) {_minValue = value;}
+                                               if (value > _maxValue) {_maxValue = value;}
+
+                                               _hasData = true;
+                                               _pointHasData[i-1] = true;
+                                       }
+                               }
+                               // Exchange points
+                               prevPrevPoint = prevPoint;
+                               prevPoint = point;
+                       }
+               }
+       }
+
+       /**
+        * @return text description including units
+        */
+       public String getLabel()
+       {
+               return I18nManager.getText("fieldname.speed") + " ("
+                       + I18nManager.getText(_metric?"units.kmh":"units.mph") + ")";
+       }
+
+       /**
+        * @return key for message when no speeds present
+        */
+       public String getNoDataKey() {
+               return "display.notimestamps";
+       }
+}
diff --git a/tim/prune/jpeg/ExifGateway.java b/tim/prune/jpeg/ExifGateway.java
new file mode 100644 (file)
index 0000000..5420ea6
--- /dev/null
@@ -0,0 +1,80 @@
+package tim.prune.jpeg;
+
+import java.io.File;
+
+import javax.swing.JOptionPane;
+
+import tim.prune.I18nManager;
+
+/**
+ * Skeleton gateway to the Exif functions.
+ * This is required by Debian to divert Exif handling
+ * to the external libmetadata-extractor-java library
+ * instead of the included modified routines.
+ *
+ * To use the internal routines, set the USE_INTERNAL_LIBRARY flag to true
+ * and include the internal classes in the compiled jar.
+ * To use the external library, set the USE_INTERNAL_LIBRARY flag to false
+ * and do not export the internal classes.
+ */
+public abstract class ExifGateway
+{
+       // *********************************************************
+       // TODO: Check this exif library flag before releasing!
+       /** Flag to specify internal or external library */
+       private static final boolean USE_INTERNAL_LIBRARY = true;
+       // *********************************************************
+
+       /** Library object to call */
+       private static ExifLibrary _exifLibrary = null;
+       /** Flag to set whether failure warning has already been shown */
+       private static boolean _exifFailWarned = false;
+
+       /** Static block to initialise library */
+       static
+       {
+               String libraryClass = USE_INTERNAL_LIBRARY?"InternalExifLibrary":"ExternalExifLibrary";
+               try
+               {
+                       _exifLibrary = (ExifLibrary) Class.forName("tim.prune.jpeg." + libraryClass).newInstance();
+               }
+               catch (Throwable nolib) {_exifLibrary = null;}
+       }
+
+
+       /**
+        * Get the Jpeg data from the given file
+        * @param inFile file to read
+        * @return jpeg data, or null if none found
+        */
+       public static JpegData getJpegData(File inFile)
+       {
+               try
+               {
+                       // Call library (if found)
+                       if (_exifLibrary != null) {
+                               JpegData data = _exifLibrary.getJpegData(inFile);
+                               return data;
+                       }
+               }
+               catch (LinkageError nolib) {}
+               // Not successful - warn if necessary
+               if (!_exifFailWarned)
+               {
+                       JOptionPane.showMessageDialog(null, I18nManager.getText("error.jpegload.exifreadfailed"),
+                               I18nManager.getText("error.jpegload.dialogtitle"), JOptionPane.WARNING_MESSAGE);
+                       _exifFailWarned = true;
+               }
+               return null;
+       }
+
+       /**
+        * @return key to use to describe library, matching key for about dialog
+        */
+       public static String getDescriptionKey()
+       {
+               String key = USE_INTERNAL_LIBRARY?"internal":"external";
+               if (_exifLibrary == null || !_exifLibrary.looksOK()) {key = key + ".failed";}
+               return key;
+       }
+}
diff --git a/tim/prune/jpeg/ExifLibrary.java b/tim/prune/jpeg/ExifLibrary.java
new file mode 100644 (file)
index 0000000..8d00617
--- /dev/null
@@ -0,0 +1,15 @@
+package tim.prune.jpeg;
+
+import java.io.File;
+
+/**
+ * Interface satisfied by both internal and external Exif implementations
+ */
+public interface ExifLibrary
+{
+       /** Get the Jpeg data from the given file */
+       public JpegData getJpegData(File inFile);
+
+       /** Check that dependencies are resolved */
+       public boolean looksOK();
+}
diff --git a/tim/prune/jpeg/ExternalExifLibrary.java b/tim/prune/jpeg/ExternalExifLibrary.java
new file mode 100644 (file)
index 0000000..b9cd1fd
--- /dev/null
@@ -0,0 +1,120 @@
+package tim.prune.jpeg;
+
+import java.io.File;
+
+import com.drew.lang.Rational;
+import com.drew.metadata.Directory;
+import com.drew.metadata.Metadata;
+import com.drew.metadata.exif.ExifDirectory;
+import com.drew.metadata.exif.ExifReader;
+import com.drew.metadata.exif.GpsDirectory;
+
+/**
+ * Class to act as a gateway into the external exif library functions.
+ * This should be the only class with dependence on the lib-metadata-extractor-java
+ * classes (which are NOT delivered with Prune).
+ * This class will not compile without this extra dependency (but is not required if
+ * the ExifGateway uses the InternalExifLibrary instead).
+ * Should not be included if the internal library will be used (from jpeg.drew package).
+ */
+public class ExternalExifLibrary implements ExifLibrary
+{
+       /**
+        * Use the _external_ exif library to get the data from the given file
+        * @param inFile file to access
+        * @return Jpeg data if available, otherwise null
+        */
+       public JpegData getJpegData(File inFile)
+       {
+               JpegData data = new JpegData();
+               // Read exif data from picture
+               try
+               {
+                       Metadata metadata = new Metadata();
+                       new ExifReader(inFile).extract(metadata);
+                       if (metadata.containsDirectory(GpsDirectory.class))
+                       {
+                               Directory gpsdir = metadata.getDirectory(GpsDirectory.class);
+                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_LATITUDE)
+                                       && gpsdir.containsTag(GpsDirectory.TAG_GPS_LONGITUDE)
+                                       && gpsdir.containsTag(GpsDirectory.TAG_GPS_LATITUDE_REF)
+                                       && gpsdir.containsTag(GpsDirectory.TAG_GPS_LONGITUDE_REF))
+                               {
+                                       data.setLatitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LATITUDE_REF));
+                                       Rational[] latRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LATITUDE);
+                                       data.setLatitude(new double[] {latRats[0].doubleValue(),
+                                               latRats[1].doubleValue(), latRats[2].doubleValue()});
+                                       data.setLongitudeRef(gpsdir.getString(GpsDirectory.TAG_GPS_LONGITUDE_REF));
+                                       Rational[] lonRats = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_LONGITUDE);
+                                       data.setLongitude(new double[] {lonRats[0].doubleValue(),
+                                               lonRats[1].doubleValue(), lonRats[2].doubleValue()});
+                               }
+
+                               // Altitude (if present)
+                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_ALTITUDE) && gpsdir.containsTag(GpsDirectory.TAG_GPS_ALTITUDE_REF))
+                               {
+                                       data.setAltitude(gpsdir.getRational(GpsDirectory.TAG_GPS_ALTITUDE).intValue());
+                                       byte altRef = (byte) gpsdir.getInt(GpsDirectory.TAG_GPS_ALTITUDE_REF);
+                                       data.setAltitudeRef(altRef);
+                               }
+
+                               // Timestamp and datestamp (if present)
+                               final int TAG_GPS_DATESTAMP = 0x001d;
+                               if (gpsdir.containsTag(GpsDirectory.TAG_GPS_TIME_STAMP) && gpsdir.containsTag(TAG_GPS_DATESTAMP))
+                               {
+                                       Rational[] times = gpsdir.getRationalArray(GpsDirectory.TAG_GPS_TIME_STAMP);
+                                       data.setGpsTimestamp(new int[] {times[0].intValue(), times[1].intValue(),
+                                               times[2].intValue()});
+                                       Rational[] dates = gpsdir.getRationalArray(TAG_GPS_DATESTAMP);
+                                       data.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});
+                               }
+                       }
+
+                       // Tags from Exif directory
+                       if (metadata.containsDirectory(ExifDirectory.class))
+                       {
+                               Directory exifdir = metadata.getDirectory(ExifDirectory.class);
+
+                               // Take time and date from exif tags if haven't got it already from GPS
+                               if (data.getGpsDatestamp() == null && exifdir.containsTag(ExifDirectory.TAG_DATETIME_ORIGINAL)) {
+                                       data.setOriginalTimestamp(exifdir.getString(ExifDirectory.TAG_DATETIME_ORIGINAL));
+                               }
+
+                               // Photo rotation code
+                               if (exifdir.containsTag(ExifDirectory.TAG_ORIENTATION)) {
+                                       data.setOrientationCode(exifdir.getInt(ExifDirectory.TAG_ORIENTATION));
+                                       // NOTE: this presumably takes the _last_ orientation value found, not the first.
+                               }
+
+                               // Thumbnail
+                               if (exifdir.containsTag(ExifDirectory.TAG_THUMBNAIL_DATA))
+                               {
+                                       // Make a copy of the byte data rather than keeping a reference to extracted array
+                                       byte[] tdata = exifdir.getByteArray(ExifDirectory.TAG_THUMBNAIL_DATA);
+                                       byte[] thumb = new byte[tdata.length];
+                                       System.arraycopy(tdata, 0, thumb, 0, tdata.length);
+                                       data.setThumbnailImage(thumb);
+                               }
+                       }
+
+               }
+               catch (Exception e) {
+                       // Exception reading metadata, just ignore it
+               }
+               return data;
+       }
+
+       /**
+        * Check whether the exifreader class can be correctly resolved
+        * @return true if it looks ok
+        */
+       public boolean looksOK()
+       {
+               try {
+                       String test = ExifReader.class.getName();
+                       if (test != null) return true;
+               }
+               catch (LinkageError le) {}
+               return false;
+       }
+}
diff --git a/tim/prune/jpeg/InternalExifLibrary.java b/tim/prune/jpeg/InternalExifLibrary.java
new file mode 100644 (file)
index 0000000..c8b1708
--- /dev/null
@@ -0,0 +1,42 @@
+package tim.prune.jpeg;
+
+import java.io.File;
+import tim.prune.jpeg.drew.ExifReader;
+import tim.prune.jpeg.drew.JpegException;
+
+/**
+ * Class to act as a gateway into the internal exif library functions.
+ * This should be the only class with dependence on the jpeg.drew package.
+ * Should not be included if external library will be used (eg Debian).
+ */
+public class InternalExifLibrary implements ExifLibrary
+{
+       /**
+        * Use the _internal_ exif library to get the data from the given file
+        * @param inFile file to access
+        * @return Jpeg data if available, otherwise null
+        */
+       public JpegData getJpegData(File inFile)
+       {
+               JpegData data = null;
+               try {
+                       data = new ExifReader(inFile).extract();
+               }
+               catch (JpegException jpe) {} // data remains null
+               return data;
+       }
+
+       /**
+        * Check whether the exifreader class can be correctly resolved
+        * @return true if it looks ok
+        */
+       public boolean looksOK()
+       {
+               try {
+                       String test = ExifReader.class.getName();
+                       if (test != null) return true;
+               }
+               catch (LinkageError le) {}
+               return false;
+       }
+}
similarity index 70%
rename from tim/prune/drew/jpeg/JpegData.java
rename to tim/prune/jpeg/JpegData.java
index 623fc3480709c3658c28ee74551a98af56483961..e1ed4c4753aa12c100d06f70925b57b7465f07d2 100644 (file)
@@ -1,7 +1,6 @@
-package tim.prune.drew.jpeg;
+package tim.prune.jpeg;
 
 import java.util.ArrayList;
-import java.util.List;
 
 /**
  * Class to hold the GPS data extracted from a Jpeg including position and time
@@ -12,11 +11,12 @@ public class JpegData
        private char _latitudeRef = '\0';
        private char _longitudeRef = '\0';
        private byte _altitudeRef = 0;
-       private Rational[] _latitude = null;
-       private Rational[] _longitude = null;
-       private Rational   _altitude = null;
-       private Rational[] _gpsTimestamp = null;
-       private Rational[] _gpsDatestamp = null;
+       private double[] _latitude = null;
+       private double[] _longitude = null;
+       private int _altitude = -1;
+       private boolean _altitudePresent = false;
+       private int[] _gpsTimestamp = null;
+       private int[] _gpsDatestamp = null;
        private String _originalTimestamp = null;
        private int _orientationCode = -1;
        private byte[] _thumbnail = null;
@@ -38,15 +38,6 @@ public class JpegData
                return _exifDataPresent;
        }
 
-       /**
-        * Set the latitude reference (N/S)
-        * @param inChar character representing reference
-        */
-       public void setLatitudeRef(char inChar)
-       {
-               _latitudeRef = inChar;
-       }
-
        /**
         * Set the latitude reference (N/S)
         * @param inString string containing reference
@@ -54,28 +45,19 @@ public class JpegData
        public void setLatitudeRef(String inString)
        {
                if (inString != null && inString.length() == 1)
-                       setLatitudeRef(inString.charAt(0));
+                       _latitudeRef = inString.charAt(0);
        }
 
        /**
         * Set the latitude
-        * @param inValues array of three Rationals for deg-min-sec
+        * @param inValues array of three doubles for deg-min-sec
         */
-       public void setLatitude(Rational[] inValues)
+       public void setLatitude(double[] inValues)
        {
                if (inValues != null && inValues.length == 3)
                        _latitude = inValues;
        }
 
-       /**
-        * Set the longitude reference (E/W)
-        * @param inChar character representing reference
-        */
-       public void setLongitudeRef(char inChar)
-       {
-               _longitudeRef = inChar;
-       }
-
        /**
         * Set the longitude reference (E/W)
         * @param inString string containing reference
@@ -83,14 +65,14 @@ public class JpegData
        public void setLongitudeRef(String inString)
        {
                if (inString != null && inString.length() == 1)
-                       setLongitudeRef(inString.charAt(0));
+                       _longitudeRef = inString.charAt(0);
        }
 
        /**
         * Set the longitude
-        * @param inValues array of three Rationals for deg-min-sec
+        * @param inValues array of three doubles for deg-min-sec
         */
-       public void setLongitude(Rational[] inValues)
+       public void setLongitude(double[] inValues)
        {
                if (inValues != null && inValues.length == 3)
                        _longitude = inValues;
@@ -107,27 +89,28 @@ public class JpegData
 
        /**
         * Set the altitude
-        * @param inRational Rational number representing altitude
+        * @param inValue integer representing altitude
         */
-       public void setAltitude(Rational inRational)
+       public void setAltitude(int inValue)
        {
-               _altitude = inRational;
+               _altitude = inValue;
+               _altitudePresent = true;
        }
 
        /**
         * Set the Gps timestamp
-        * @param inValues array of Rationals holding timestamp
+        * @param inValues array of ints holding timestamp
         */
-       public void setGpsTimestamp(Rational[] inValues)
+       public void setGpsTimestamp(int[] inValues)
        {
                _gpsTimestamp = inValues;
        }
 
        /**
         * Set the Gps datestamp
-        * @param inValues array of Rationals holding datestamp
+        * @param inValues array of ints holding datestamp
         */
-       public void setGpsDatestamp(Rational[] inValues)
+       public void setGpsDatestamp(int[] inValues)
        {
                _gpsDatestamp = inValues;
        }
@@ -155,19 +138,21 @@ public class JpegData
        /** @return latitude ref as char */
        public char getLatitudeRef() { return _latitudeRef; }
        /** @return latitude as array of 3 Rationals */
-       public Rational[] getLatitude() { return _latitude; }
+       public double[] getLatitude() { return _latitude; }
        /** @return longitude ref as char */
        public char getLongitudeRef() { return _longitudeRef; }
-       /** @return longitude as array of 3 Rationals */
-       public Rational[] getLongitude() { return _longitude; }
+       /** @return longitude as array of 3 doubles */
+       public double[] getLongitude() { return _longitude; }
        /** @return altitude ref as byte (should be 0) */
        public byte getAltitudeRef() { return _altitudeRef; }
-       /** @return altitude as Rational */
-       public Rational getAltitude() { return _altitude; }
-       /** @return Gps timestamp as array of 3 Rationals */
-       public Rational[] getGpsTimestamp() { return _gpsTimestamp; }
-       /** @return Gps datestamp as array of 3 Rationals */
-       public Rational[] getGpsDatestamp() { return _gpsDatestamp; }
+       /** @return true if altitude present */
+       public boolean hasAltitude() { return _altitudePresent; }
+       /** @return altitude as int */
+       public int getAltitude() { return _altitude; }
+       /** @return Gps timestamp as array of 3 ints */
+       public int[] getGpsTimestamp() { return _gpsTimestamp; }
+       /** @return Gps datestamp as array of 3 ints */
+       public int[] getGpsDatestamp() { return _gpsDatestamp; }
        /** @return orientation code (1 to 8) */
        public int getOrientationCode() { return _orientationCode; }
        /** @return original timestamp as string */
@@ -200,7 +185,7 @@ public class JpegData
         * @return true if data looks valid, ie has at least lat and long
         *  (altitude and timestamp optional).
         */
-       public boolean isValid()
+       public boolean isGpsValid()
        {
                return (_latitudeRef == 'N' || _latitudeRef == 'n' || _latitudeRef == 'S' || _latitudeRef == 's')
                        && _latitude != null
@@ -238,7 +223,7 @@ public class JpegData
        /**
         * @return all errors as a list
         */
-       public List<String> getErrors()
+       public ArrayList<String> getErrors()
        {
                return _errors;
        }
similarity index 92%
rename from tim/prune/drew/jpeg/ExifReader.java
rename to tim/prune/jpeg/drew/ExifReader.java
index 0084b87b169a6b0913f386e677c34e15aaeb757f..50a72d0caffd37c987f9897b9ec2ff2860a83994 100644 (file)
@@ -1,8 +1,10 @@
-package tim.prune.drew.jpeg;\r
+package tim.prune.jpeg.drew;\r
 \r
 import java.io.File;\r
 import java.util.HashMap;\r
 \r
+import tim.prune.jpeg.JpegData;\r
+\r
 /**\r
  * Extracts Exif data from a JPEG header segment\r
  * Based on Drew Noakes' Metadata extractor at http://drewnoakes.com\r
@@ -336,25 +338,29 @@ public class ExifReader
                                inMetadata.setLatitudeRef(readString(inTagValueOffset, inFormatCode, inComponentCount));\r
                                break;\r
                        case TAG_GPS_LATITUDE:\r
-                               inMetadata.setLatitude(readRationalArray(inTagValueOffset, inFormatCode, inComponentCount));\r
+                               Rational[] latitudes = readRationalArray(inTagValueOffset, inFormatCode, inComponentCount);\r
+                               inMetadata.setLatitude(new double[] {latitudes[0].doubleValue(), latitudes[1].doubleValue(), latitudes[2].doubleValue()});\r
                                break;\r
                        case TAG_GPS_LONGITUDE_REF:\r
                                inMetadata.setLongitudeRef(readString(inTagValueOffset, inFormatCode, inComponentCount));\r
                                break;\r
                        case TAG_GPS_LONGITUDE:\r
-                               inMetadata.setLongitude(readRationalArray(inTagValueOffset, inFormatCode, inComponentCount));\r
+                               Rational[] longitudes = readRationalArray(inTagValueOffset, inFormatCode, inComponentCount);\r
+                               inMetadata.setLongitude(new double[] {longitudes[0].doubleValue(), longitudes[1].doubleValue(), longitudes[2].doubleValue()});\r
                                break;\r
                        case TAG_GPS_ALTITUDE_REF:\r
                                inMetadata.setAltitudeRef(_data[inTagValueOffset]);\r
                                break;\r
                        case TAG_GPS_ALTITUDE:\r
-                               inMetadata.setAltitude(readRational(inTagValueOffset, inFormatCode, inComponentCount));\r
+                               inMetadata.setAltitude(readRational(inTagValueOffset, inFormatCode, inComponentCount).intValue());\r
                                break;\r
                        case TAG_GPS_TIMESTAMP:\r
-                               inMetadata.setGpsTimestamp(readRationalArray(inTagValueOffset, inFormatCode, inComponentCount));\r
+                               Rational[] times = readRationalArray(inTagValueOffset, inFormatCode, inComponentCount);\r
+                               inMetadata.setGpsTimestamp(new int[] {times[0].intValue(), times[1].intValue(), times[2].intValue()});\r
                                break;\r
                        case TAG_GPS_DATESTAMP:\r
-                               inMetadata.setGpsDatestamp(readRationalArray(inTagValueOffset, inFormatCode, inComponentCount));\r
+                               Rational[] dates = readRationalArray(inTagValueOffset, inFormatCode, inComponentCount);\r
+                               inMetadata.setGpsDatestamp(new int[] {dates[0].intValue(), dates[1].intValue(), dates[2].intValue()});\r
                                break;\r
                        default: // ignore all other tags\r
                }\r
similarity index 93%
rename from tim/prune/drew/jpeg/JpegException.java
rename to tim/prune/jpeg/drew/JpegException.java
index 5c757666886fac8dfb3e294a2778486dbbbda9ce..d85a3b7f1b035b75f59e9f446ed9be10f0e88f62 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.drew.jpeg;
+package tim.prune.jpeg.drew;
 
 /**
  * Class to indicate a fatal exception processing a jpeg,
similarity index 95%
rename from tim/prune/drew/jpeg/JpegSegmentData.java
rename to tim/prune/jpeg/drew/JpegSegmentData.java
index 8541a08b9b146eae3ce938b4b9d858b655fed890..4b56cbe9c57a6ff12a7475c5590574d114722d83 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.drew.jpeg;\r
+package tim.prune.jpeg.drew;\r
 \r
 import java.util.ArrayList;\r
 import java.util.HashMap;\r
similarity index 96%
rename from tim/prune/drew/jpeg/JpegSegmentReader.java
rename to tim/prune/jpeg/drew/JpegSegmentReader.java
index 20eb83c2d65f18f10588b9e18bc2e23fec463e0b..382e9f5d1e860b439aca966b9e0c87939cde542d 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.drew.jpeg;\r
+package tim.prune.jpeg.drew;\r
 \r
 import java.io.*;\r
 \r
similarity index 94%
rename from tim/prune/drew/jpeg/Rational.java
rename to tim/prune/jpeg/drew/Rational.java
index e522935159473d673b0cdf55be642e4bd78078d9..3c83b9f5d88595fadb140d4dbb4a82532d6cf495 100644 (file)
@@ -1,4 +1,4 @@
-package tim.prune.drew.jpeg;\r
+package tim.prune.jpeg.drew;\r
 \r
 /**\r
  * Immutable class for holding a rational number without loss of precision.\r
index 11de10f6e98214d40cee388dd7a4a54dc3417fd2..109aeb85bd7f694fe025ff14da00f50a7f55b86c 100644 (file)
@@ -3,31 +3,30 @@
 
 # Menu entries
 menu.file=L\u00eaer
-menu.file.open=Open L\u00eaer
 menu.file.addphotos=Voeg Fotos By
 menu.file.save=Stoor
 menu.file.exit=Gaan Uit
-menu.edit=Redigeer
-menu.edit.undo=Herroep
-menu.edit.clearundo=Herroep Lys Skoonmaak
-menu.edit.editpoint=Redigeer Punt
-menu.edit.deletepoint=Punt Uitvee
-menu.edit.deleterange=Reeks Uitvee
-menu.edit.deletemarked=Gemerkde Punt Uitvee
-menu.edit.interpolate=Interpoleer
-menu.edit.average=Gemiddelde Seleksie
-menu.edit.reverse=Reeks Omkeer
-menu.edit.mergetracksegments=Saamvoeg van spoor segmente
-menu.edit.rearrange=Herrangskik bakens
-menu.edit.rearrange.start=Bakens na begin van l\u00eaer
-menu.edit.rearrange.end=Bakens na einde van l\u00eaer
-menu.edit.rearrange.nearest=Beweeg elk na naaste spoor punt
-menu.edit.cutandmove=Sny en skuif seleksie
-menu.select=Selekteer
-menu.select.all=Selekteer Alles
-menu.select.none=Selekteer Niks
-menu.select.start=Stel Reeks Begin
-menu.select.end=Stel Reeks Einde
+menu.track.undo=Herroep
+menu.track.clearundo=Herroep Lys Skoonmaak
+menu.point.editpoint=Redigeer Punt
+menu.point.deletepoint=Punt Uitvee
+menu.range.deleterange=Reeks Uitvee
+menu.track.deletemarked=Gemerkde Punt Uitvee
+menu.range.interpolate=Interpoleer
+menu.range.average=Gemiddelde Seleksie
+menu.range.reverse=Reeks Omkeer
+menu.range.mergetracksegments=Saamvoeg van spoor segmente
+menu.track.rearrange=Herrangskik bakens
+menu.track.rearrange.start=Bakens na begin van l\u00eaer
+menu.track.rearrange.end=Bakens na einde van l\u00eaer
+menu.track.rearrange.nearest=Beweeg elk na naaste spoor punt
+menu.range.cutandmove=Sny en skuif seleksie
+menu.range=Reeks
+menu.point=Punt
+menu.range.all=Selekteer Alles
+menu.range.none=Selekteer Niks
+menu.range.start=Stel Reeks Begin
+menu.range.end=Stel Reeks Einde
 menu.photo=Foto
 menu.photo.saveexif=Stoor na EXIF
 menu.photo.connect=Las foto by huidige punt
@@ -40,6 +39,7 @@ menu.view.browser.openstreetmap=Openstreetmap
 menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Yahoo Kaarte
 menu.view.browser.bing=Bing Kaarte
+menu.settings=Stellings
 menu.help=Hulp
 # Popup menu for map
 menu.map.zoomin=Zoom in
@@ -50,7 +50,26 @@ menu.map.connect=Connekteer baan punte
 menu.map.autopan=Automatiese Skuif van Kyk Venster
 menu.map.showmap=Wys Kaart
 
+# Alt keys for menus
+altkey.menu.file=L
+altkey.menu.range=R
+altkey.menu.point=P
+altkey.menu.view=K
+altkey.menu.photo=F
+altkey.menu.settings=S
+altkey.menu.help=H
+
+# Ctrl shortcuts for menu items
+shortcut.menu.file.open=O
+shortcut.menu.file.load=L
+shortcut.menu.file.save=S
+shortcut.menu.track.undo=Z
+shortcut.menu.edit.compress=C
+shortcut.menu.range.all=A
+shortcut.menu.help.help=H
+
 # Functions
+function.open=Open L\u00eaer
 function.loadfromgps=Laai van GPS data
 function.sendtogps=Stuur van GPS data
 function.exportkml=KML Uitvoer
index 26e2b659f2f03eeddd322de36aace4f2cdcf90ab..95af0aa1d584c4e610c48eb2941cad479a1aaf72 100644 (file)
@@ -3,32 +3,31 @@
 
 # Menu entries
 menu.file=Datei
-menu.file.open=Datei Ã¶ffnen
 menu.file.addphotos=Fotos laden
 menu.file.save=Speichern
 menu.file.exit=Beenden
 menu.track=Track
-menu.edit.undo=Rückgängig
-menu.edit.clearundo=Liste der letzten Ã„nderungen löschen
-menu.edit.editpoint=Punkt bearbeiten
-menu.edit.deletepoint=Punkt löschen
-menu.edit.deleterange=Bereich löschen
-menu.edit.deletemarked=Komprimierte Punkte löschen
-menu.edit.interpolate=Interpolieren
-menu.edit.average=Durchschnitt berechnen
-menu.edit.reverse=Bereich umkehren
-menu.edit.mergetracksegments=Trackabschnitte verbinden
-menu.edit.rearrange=Wegpunkte reorganisieren
-menu.edit.rearrange.start=Alle Wegpunkte zum Anfang
-menu.edit.rearrange.end=Alle Wegpunkte ans Ende
-menu.edit.rearrange.nearest=Jeden Wegpunkt zum nächsten Trackpunkt verschieben
-menu.edit.cutandmove=Schneiden und verschieben
+menu.track.undo=Rückgängig
+menu.track.clearundo=Liste der letzten Ã„nderungen löschen
+menu.track.deletemarked=Komprimierte Punkte löschen
+menu.track.rearrange=Wegpunkte reorganisieren
+menu.track.rearrange.start=Alle Wegpunkte zum Anfang
+menu.track.rearrange.end=Alle Wegpunkte ans Ende
+menu.track.rearrange.nearest=Jeden Wegpunkt zum nächsten Trackpunkt verschieben
 menu.range=Bereich
+menu.range.all=Alles markieren
+menu.range.none=Nichts markieren
+menu.range.start=Startpunkt setzen
+menu.range.end=Endpunkt setzen
+menu.range.deleterange=Bereich löschen
+menu.range.interpolate=Interpolieren
+menu.range.average=Durchschnitt berechnen
+menu.range.reverse=Bereich umkehren
+menu.range.mergetracksegments=Trackabschnitte verbinden
+menu.range.cutandmove=Schneiden und verschieben
 menu.point=Punkt
-menu.select.all=Alles markieren
-menu.select.none=Nichts markieren
-menu.select.start=Startpunkt setzen
-menu.select.end=Endpunkt setzen
+menu.point.editpoint=Punkt bearbeiten
+menu.point.deletepoint=Punkt löschen
 menu.photo=Foto
 menu.photo.saveexif=Exif Daten speichern
 menu.photo.connect=Mit Punkt verknüpfen
@@ -37,6 +36,7 @@ menu.photo.delete=Foto entfernen
 menu.view=Ansicht
 menu.view.browser=Karte in Browser
 menu.settings=Einstellungen
+menu.settings.onlinemode=Karten aus dem Internet laden
 menu.help=Hilfe
 # Popup menu for map
 menu.map.zoomin=Hineinzoomen
@@ -62,12 +62,13 @@ altkey.menu.help=H
 shortcut.menu.file.open=O
 shortcut.menu.file.load=L
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=K
-shortcut.menu.select.all=A
+shortcut.menu.range.all=A
 shortcut.menu.help.help=H
 
 # Functions
+function.open=Datei Ã¶ffnen
 function.loadfromgps=Vom GPS laden
 function.sendtogps=zum GPS schicken
 function.exportkml=KML exportieren
@@ -90,6 +91,7 @@ function.setpaths=Programmpfade setzen
 function.setcolours=Farben einstellen
 function.setlanguage=Sprache einstellen
 function.getgpsies=Gpsies Tracks holen
+function.lookupsrtm=Höhendaten von SRTM holen
 function.duplicatepoint=Punkt verdoppeln
 function.correlatephotos=Fotos korrelieren
 function.rearrangephotos=Fotos reorganisieren
@@ -101,6 +103,7 @@ function.showkeys=Tastenkombinationen anzeigen
 function.about=Ãœber Prune
 function.checkversion=Nach neuen Versionen suchen
 function.saveconfig=Einstellungen speichern
+function.diskcache=Karten auf Disk speichern
 
 # Dialogs
 dialog.exit.confirm.title=Prune beenden
@@ -126,6 +129,7 @@ dialog.openoptions.deliminfo.records=Aufnahmen, mit
 dialog.openoptions.deliminfo.fields=Feldern
 dialog.openoptions.deliminfo.norecords=Keine Rekords
 dialog.openoptions.altitudeunits=Höhe Maßeinheiten
+dialog.open.contentsdoubled=Diese Datei enthält zwei Kopien von jedem Punkt,\neinmal als Waypoint und einmal als Trackpunkt.
 dialog.jpegload.subdirectories=Unterordner mit durchsuchen
 dialog.jpegload.loadjpegswithoutcoords=Auch Fotos ohne Koordinaten laden
 dialog.jpegload.loadjpegsoutsidearea=Auch Fotos ausserhalb vom Track laden
@@ -233,9 +237,14 @@ dialog.distances.column.to=Zum Punkt
 dialog.distances.currentpoint=Aktueller Punkt
 dialog.distances.toofewpoints=Diese Funktion braucht Wegpunkte um die Distanzen zu berechnen
 dialog.fullrangedetails.intro=Hier sind die Details vom markierten Bereich
-dialog.setmapbg.cyclemap=Fahrradkarte
-dialog.setmapbg.other=Andere
-dialog.setmapbg.server=Server URL
+dialog.setmapbg.intro=Eine von den Quellen auswählen, oder eine neue hinzufügen
+dialog.addmapsource.title=Neue Kartequelle hinzufügen
+dialog.addmapsource.sourcename=Sourcename
+dialog.addmapsource.layer1url=URL für erste Ebene
+dialog.addmapsource.layer2url=URL für obere Ebene (falls nötig)
+dialog.addmapsource.maxzoom=Maximales Zoom
+dialog.addmapsource.cloudstyle=Stilnummer
+dialog.addmapsource.noname=Unbenannt
 dialog.gpsies.column.name=Track Name
 dialog.gpsies.column.length=Länge
 dialog.gpsies.description=Beschreibung
@@ -297,6 +306,11 @@ dialog.about.systeminfo.povray=Povray installiert
 dialog.about.systeminfo.exiftool=Exiftool installiert
 dialog.about.systeminfo.gpsbabel=Gpsbabel installiert
 dialog.about.systeminfo.gnuplot=Gnuplot installiert
+dialog.about.systeminfo.exiflib=Exif Bibliothek
+dialog.about.systeminfo.exiflib.internal=Intern
+dialog.about.systeminfo.exiflib.internal.failed=Intern (nicht gefunden)
+dialog.about.systeminfo.exiflib.external=Extern
+dialog.about.systeminfo.exiflib.external.failed=Extern (nicht gefunden)
 dialog.about.yes=Ja
 dialog.about.no=Nein
 dialog.about.credits=Credits
@@ -317,7 +331,7 @@ dialog.checkversion.releasedate1=Diese neue Version ist am
 dialog.checkversion.releasedate2=veröffentlicht worden.
 dialog.checkversion.download=Um die neue Version herunterzuladen, gehen Sie zu http://activityworkshop.net/software/prune/download.html.
 dialog.keys.intro=Anstatt die Maus können Sie diesen Taste-Kombinationen nutzen
-dialog.keys.keylist=<table><tr><td>Pfeil Tasten</td><td>Karte verschieben</td></tr><tr><td>Strg + links, rechts Pfeil</td><td>Vorherigen oder nächsten Punkt markieren</td></tr><tr><td>Strg + auf, abwärts Pfeil</td><td>Ein- oder Auszoomen</td></tr><tr><td>Entf</td><td>Aktuellen Punkt entfernen</td></tr></table>
+dialog.keys.keylist=<table><tr><td>Pfeil Tasten</td><td>Karte verschieben</td></tr><tr><td>Strg + links, rechts Pfeil</td><td>Vorherigen oder nächsten Punkt markieren</td></tr><tr><td>Strg + auf, abwärts Pfeil</td><td>Ein- oder Auszoomen</td></tr><tr><td>Strg + Bild auf, ab</td><td>Vorherigen oder nächsten Segment markieren</td></tr><tr><td>Strg + Pos1, Ende</td><td>Ersten oder letzten Punkt markieren</td></tr><tr><td>Entf</td><td>Aktuellen Punkt entfernen</td></tr></table>
 dialog.saveconfig.desc=Die folgende Einstellungen können gespeichert werden :
 dialog.saveconfig.prune.trackdirectory=Datenverzeichnis
 dialog.saveconfig.prune.photodirectory=Fotoverzeichnis
@@ -330,13 +344,15 @@ dialog.saveconfig.prune.metricunits=Metrische Einheiten verwenden?
 dialog.saveconfig.prune.gnuplotpath=Gnuplot Pfad
 dialog.saveconfig.prune.gpsbabelpath=Gpsbabel Pfad
 dialog.saveconfig.prune.exiftoolpath=Exiftool Pfad
-dialog.saveconfig.prune.mapserverindex=Kartenserver Index
-dialog.saveconfig.prune.mapserverurl=Kartenserver URL
+dialog.saveconfig.prune.mapsource=Kartenserver Index
+dialog.saveconfig.prune.mapsourcelist=Kartenservers
+dialog.saveconfig.prune.diskcache=Kartenordner
 dialog.saveconfig.prune.kmzimagewidth=Bildbreite in KMZ
 dialog.saveconfig.prune.kmzimageheight=Bildhöhe in KMZ
 dialog.saveconfig.prune.colourscheme=Farbenschema
 dialog.saveconfig.prune.kmltrackcolour=KML Trackfarbe
 dialog.setpaths.intro=Sie können hier die Pfade für externe Applikationen setzen:
+dialog.setpaths.found=Pfad gefunden?
 dialog.addaltitude.noaltitudes=Der markierten Bereich enthält keine Höhenangaben
 dialog.addaltitude.desc=Höhenverschiebung aufzurechnen
 dialog.setcolours.intro=Klicken Sie auf einer Farbe um sie zu Ã¤ndern
@@ -357,6 +373,10 @@ dialog.setlanguage.secondintro=Sie m
 dialog.setlanguage.language=Sprache
 dialog.setlanguage.languagefile=Sprache Datei
 dialog.setlanguage.endmessage=Nun speichern Sie Ihre Einstellungen und starten Sie Prune neu\num die neue Sprache zu verwenden.
+dialog.diskcache.save=Karten zum Disk speichern
+dialog.diskcache.dir=Kartenordner
+dialog.diskcache.createdir=Ordner kreieren
+dialog.diskcache.nocreate=Ordner wurde nicht kreiert
 
 # 3d window
 dialog.3d.title=Prune 3D Ansicht
@@ -393,6 +413,8 @@ confirm.correlate.multi=Fotos wurden korreliert
 confirm.createpoint=Punkt kreiert
 confirm.rotatephoto=Foto umgedreht
 confirm.running=In Bearbeitung ...
+confirm.lookupsrtm1=Es wurde
+confirm.lookupsrtm2=Höhenwerte gefunden
 
 # Buttons
 button.ok=OK
@@ -422,6 +444,8 @@ button.showwebpage=Webseite anzeigen
 button.check=Prüfen
 button.resettodefaults=Zurücksetzen
 button.browse=Durchsuchen...
+button.addnew=Hinzufügen
+button.delete=Entfernen
 
 # File types
 filetype.txt=TXT Dateien
@@ -436,6 +460,7 @@ filetype.svg=SVG Dateien
 # Display components
 display.nodata=Keine Daten geladen
 display.noaltitudes=Track enthält keine Höhenangaben
+display.notimestamps=Track enthält keine Zeitstempeln
 details.trackdetails=Details vom Track
 details.notrack=Kein Track geladen
 details.track.points=Punkte
@@ -461,6 +486,7 @@ display.range.time.hours=h
 display.range.time.days=T
 details.range.avespeed=Geschwindigkeit
 details.range.avemovingspeed=Geschwindigkeit unterwegs
+details.range.maxspeed=Höchstgeschwindigkeit
 details.range.numsegments=Anzahl Abschnitte
 details.range.pace=Tempo
 details.range.gradient=Gefälle
@@ -535,6 +561,7 @@ undo.rearrangephotos=Fotos reorganisieren
 undo.rotatephoto=Foto umdrehen
 undo.createpoint=Punkt erzeugen
 undo.convertnamestotimes=Namen in Zeitstempeln verwandeln
+undo.lookupsrtm=Höhendaten von SRTM holen
 
 # Error messages
 error.save.dialogtitle=Fehler beim Speichern
@@ -558,6 +585,7 @@ error.jpegload.nofilesfound=Keine Dateien gefunden
 error.jpegload.nojpegsfound=Keine Jpeg Dateien gefunden
 error.jpegload.noexiffound=Keine EXIF Information gefunden
 error.jpegload.nogpsfound=Keine GPS Information gefunden
+error.jpegload.exifreadfailed=EXIF Aufruf fehlgeschlagen. Keine EXIF Information können gelesen werden\nohne einen internen oder externen Bibliothek.
 error.gpsload.unknown=Unbekanntes Fehler
 error.undofailed.title=Undo fehlgeschlagen
 error.undofailed.text=Operation konnte nicht rückgängig gemacht werden
@@ -571,3 +599,4 @@ error.osmimage.dialogtitle=Laden von Karten-Bildern fehlgeschlagen
 error.osmimage.failed=Laden von Karten-Bildern fehlgeschlagen. Bitte prüfen Sie die Internetverbindung.
 error.language.wrongfile=Die ausgewählte Datei scheint keine Sprache-Datei für Prune zu sein
 error.convertnamestotimes.nonames=Keine Namen konnten verwandelt werden
+error.lookupsrtm.none=Keine Höhendaten gefunden
index 5ce66f6cd689c65d35b30b5407143cc3487c93a0..faf7db30b0f8b12f044a6fc1dd00be49a2ea828d 100644 (file)
@@ -3,32 +3,31 @@
 
 # Menu entries
 menu.file=File
-menu.file.open=File Ã¶ffne
 menu.file.addphotos=Fötelis innätue
 menu.file.save=Speichere
 menu.file.exit=Beände
 menu.track=Track
-menu.edit.undo=Undo
-menu.edit.clearundo=Undo-Liste lösche
-menu.edit.editpoint=Punkt editiere
-menu.edit.deletepoint=Punkt lösche
-menu.edit.deleterange=Beriich lösche
-menu.edit.deletemarked=Komprimierte Punkte lösche
-menu.edit.interpolate=Interpoliere
-menu.edit.average=Durchschnitt uusrächne
-menu.edit.reverse=Beriich umdrähie
-menu.edit.mergetracksegments=Track Segmänte merge
-menu.edit.rearrange=Waypoints reorganisiere
-menu.edit.rearrange.start=Alli zum Aafang
-menu.edit.rearrange.end=Alli zum Ã„nde
-menu.edit.rearrange.nearest=Jede zum nöchsti Trackpunkt
-menu.edit.cutandmove=Schniide und move
+menu.track.undo=Undo
+menu.track.clearundo=Undo-Liste lösche
+menu.track.deletemarked=Komprimierte Punkte lösche
+menu.track.rearrange=Waypoints reorganisiere
+menu.track.rearrange.start=Alli zum Aafang
+menu.track.rearrange.end=Alli zum Ã„nde
+menu.track.rearrange.nearest=Jede zum nöchsti Trackpunkt
 menu.range=Beriich
+menu.range.all=Alles selektiere
+menu.range.none=Nüüt selektiere
+menu.range.start=Start setzä
+menu.range.end=Stopp setzä
+menu.range.deleterange=Beriich lösche
+menu.range.interpolate=Interpoliere
+menu.range.average=Durchschnitt uusrächne
+menu.range.reverse=Beriich umdrähie
+menu.range.mergetracksegments=Track Segmänte merge
+menu.range.cutandmove=Schniide und move
 menu.point=Punkt
-menu.select.all=Alles selektiere
-menu.select.none=Nüüt selektiere
-menu.select.start=Start setzä
-menu.select.end=Stopp setzä
+menu.point.editpoint=Punkt editiere
+menu.point.deletepoint=Punkt lösche
 menu.photo=Föteli
 menu.photo.saveexif=Exif Date speicherä
 menu.photo.connect=Mitem Punkt verbindä
@@ -37,6 +36,7 @@ menu.photo.delete=F
 menu.view=Aasicht
 menu.view.browser=Karte inem Browser
 menu.settings=Iistellige
+menu.settings.onlinemode=Karte uusem Internet lade
 menu.help=Hilfe
 # Popup menu for map
 menu.map.zoomin=Innezoome
@@ -62,12 +62,13 @@ altkey.menu.help=H
 shortcut.menu.file.open=O
 shortcut.menu.file.load=L
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=K
-shortcut.menu.select.all=A
+shortcut.menu.range.all=A
 shortcut.menu.help.help=H
 
 # Functions
+function.open=File Ã¶ffne
 function.loadfromgps=uusem GPS lade
 function.sendtogps=zum GPS schicke
 function.exportkml=KML exportierä
@@ -86,6 +87,7 @@ function.distances=Distanze
 function.fullrangedetails=Zuesätzlichi Beriichinfos
 function.setmapbg=Karte Hintegrund setzä
 function.getgpsies=Gpsies Tracks holä
+function.lookupsrtm=Höhendate vonem SRTM hole
 function.duplicatepoint=Punkt verdopplä
 function.correlatephotos=Fötelis korrelierä
 function.rearrangephotos=Fötelis reorganisierä
@@ -101,6 +103,7 @@ function.showkeys=Tastekombinatione aazeige
 function.about=Ãœber Prune
 function.checkversion=Pruef nach ne noie Version
 function.saveconfig=Iistellige speichere
+function.diskcache=Karte uufem Disk speichere
 
 # Dialogs
 dialog.exit.confirm.title=Prune beände
@@ -126,6 +129,7 @@ dialog.openoptions.deliminfo.records=Rekords, mit
 dialog.openoptions.deliminfo.fields=Fäldere
 dialog.openoptions.deliminfo.norecords=Kei Rekords
 dialog.openoptions.altitudeunits=Höchi Masseiheite
+dialog.open.contentsdoubled=Dieses File hät zwei Kopien von jädem Punkt,\neimol als Waypoint und eimol als Trackpunkt.
 dialog.jpegload.subdirectories=Subordnern au
 dialog.jpegload.loadjpegswithoutcoords=Au Fötelis ohni Koordinate
 dialog.jpegload.loadjpegsoutsidearea=Au Fötelis uuserhalb vonem Track
@@ -233,9 +237,14 @@ dialog.distances.column.to=Zum Punkt
 dialog.distances.currentpoint=Aktuelli Punkt
 dialog.distances.toofewpoints=d'Funktion bruucht Waypoints um die Dischtanze z berächne
 dialog.fullrangedetails.intro=Hier sind die Infos vonem aktuelli Beriich
-dialog.setmapbg.cyclemap=Velokarte
-dialog.setmapbg.other=Anderi
-dialog.setmapbg.server=Server URL
+dialog.setmapbg.intro=Eini von den Quällen uuswähle, oder eini neui hinzuefüge
+dialog.addmapsource.title=Neui Kartequälle hinzuefüge
+dialog.addmapsource.sourcename=Sourcename
+dialog.addmapsource.layer1url=URL für erschti Ebene
+dialog.addmapsource.layer2url=URL für oberi Ebene (falls nötig)
+dialog.addmapsource.maxzoom=Maximali Zoom
+dialog.addmapsource.cloudstyle=Stilnummere
+dialog.addmapsource.noname=Unbenannt
 dialog.gpsies.column.name=Track Name
 dialog.gpsies.column.length=Länge
 dialog.gpsies.description=Beschriebig
@@ -297,6 +306,11 @@ dialog.about.systeminfo.povray=Povray inschtalliert
 dialog.about.systeminfo.exiftool=Exiftool inschtalliert
 dialog.about.systeminfo.gpsbabel=Gpsbabel inschtalliert
 dialog.about.systeminfo.gnuplot=Gnuplot inschtalliert
+dialog.about.systeminfo.exiflib=Exif Bibliothek
+dialog.about.systeminfo.exiflib.internal=Intern
+dialog.about.systeminfo.exiflib.internal.failed=Intern (nöd gfunde)
+dialog.about.systeminfo.exiflib.external=Extärn
+dialog.about.systeminfo.exiflib.external.failed=Extärn (nöd gfunde)
 dialog.about.yes=Ja
 dialog.about.no=Nei
 dialog.about.credits=Credits
@@ -317,7 +331,7 @@ dialog.checkversion.releasedate1=Die noii Version isch am
 dialog.checkversion.releasedate2=ussecho.
 dialog.checkversion.download=Um die noii Version runterzlade, schauet Sie na http://activityworkshop.net/software/prune/download.html.
 dialog.keys.intro=Aastatt d'Muus könnet Sie diese Tastekombinationen nutze
-dialog.keys.keylist=<table><tr><td>Pfiil Taste</td><td>Karte verschiebe</td></tr><tr><td>Strg + links, rächts Pfiil</td><td>Vorherigi oder nöchsti Punkt markiere</td></tr><tr><td>Strg + uuf, aba Pfiil</td><td>Ii- oder Uusezoome</td></tr><tr><td>Entf</td><td>Aktuelli Punkt lösche</td></tr></table>
+dialog.keys.keylist=<table><tr><td>Pfiil Taste</td><td>Karte verschiebe</td></tr><tr><td>Strg + links, rächts Pfiil</td><td>Vorherigi oder nöchsti Punkt markiere</td></tr><tr><td>Strg + uuf, aba Pfiil</td><td>Ii- oder Uusezoome</td></tr><tr><td>Strg + Bild uuf, ab</td><td>Vorherigi oder nöchsti Segmänt markiere</td></tr><tr><td>Strg + Pos1, Ende</td><td>Erschti oder letschti Punkt markiere</td></tr><tr><td>Entf</td><td>Aktuelli Punkt lösche</td></tr></table>
 dialog.saveconfig.desc=Die folgendi Iinstellige könne gspeicheret werde :
 dialog.saveconfig.prune.trackdirectory=Trackverzeichnis
 dialog.saveconfig.prune.photodirectory=Föteliverzeichnis
@@ -330,13 +344,15 @@ dialog.saveconfig.prune.metricunits=Metrischi Einheite verwende?
 dialog.saveconfig.prune.gnuplotpath=Gnuplot Pfad
 dialog.saveconfig.prune.gpsbabelpath=Gpsbabel Pfad
 dialog.saveconfig.prune.exiftoolpath=Exiftool Pfad
-dialog.saveconfig.prune.mapserverindex=Kartenserver Index
-dialog.saveconfig.prune.mapserverurl=Kartenserver URL
+dialog.saveconfig.prune.mapsource=Kartenserver Index
+dialog.saveconfig.prune.mapsourcelist=Kartenservers
+dialog.saveconfig.prune.diskcache=Kartenordner
 dialog.saveconfig.prune.kmzimagewidth=Bildbreiti im KMZ
 dialog.saveconfig.prune.kmzimageheight=Bildhöchi im KMZ
 dialog.saveconfig.prune.colourscheme=Farbeschema
 dialog.saveconfig.prune.kmltrackcolour=KML Trackfarb
 dialog.setpaths.intro=Sie könnet dann die Pfade für dia Applikatione setzä:
+dialog.setpaths.found=Pfad gfunde?
 dialog.addaltitude.noaltitudes=Dr seläktierte Beriich hät keini Höchiinformation
 dialog.addaltitude.desc=Höchiverschiebig zuzutue
 dialog.setcolours.intro=Klicket Sie uuf ne Farb um sie z'verändere
@@ -357,6 +373,10 @@ dialog.setlanguage.secondintro=Sie m
 dialog.setlanguage.language=Sproch
 dialog.setlanguage.languagefile=Sproch Datei
 dialog.setlanguage.endmessage=Jetze speicheret Sie Ihri Iistellige und startet Sie Prune neu\num t noii Sproch z' verwände.
+dialog.diskcache.save=Karten uufem Disk speichere
+dialog.diskcache.dir=Kartenordner
+dialog.diskcache.createdir=Ordner kreiere
+dialog.diskcache.nocreate=Ordner isch nöd kreiert worde
 
 # 3d window
 dialog.3d.title=Prune Drüü-d Aasicht
@@ -393,6 +413,8 @@ confirm.correlate.multi=F
 confirm.createpoint=Punkt kreiert worde
 confirm.rotatephoto=Föteli umgedräit worde
 confirm.running=Am Laufe ...
+confirm.lookupsrtm1=Es sin
+confirm.lookupsrtm2=Höhenwerte gfunde
 
 # Buttons
 button.ok=OK
@@ -422,6 +444,8 @@ button.showwebpage=Websiite aazeig
 button.check=Prüefa
 button.resettodefaults=Zurücksetzä
 button.browse=Durasuechä...
+button.addnew=Hinzuefügä
+button.delete=Entfärnä
 
 # File types
 filetype.txt=TXT Dateie
@@ -436,6 +460,7 @@ filetype.svg=SVG Dateie
 # Display components
 display.nodata=Kei Date glade worde
 display.noaltitudes=Track hät kei Höhi Date
+display.notimestamps=Track hät kei Ziitstämple
 details.trackdetails=Details vom Track
 details.notrack=Kei Track glade worde
 details.track.points=Punkte
@@ -461,6 +486,7 @@ display.range.time.hours=Std
 display.range.time.days=T
 details.range.avespeed=Gschwindikeit
 details.range.avemovingspeed=Gschwindikeit ufem Wäg
+details.range.maxspeed=Höchstgschwindikeit
 details.range.numsegments=Aazahl Segmänte
 details.range.pace=Tempo
 details.range.gradient=Gefälle
@@ -535,6 +561,7 @@ undo.rearrangephotos=F
 undo.createpoint=Punkt kreierä
 undo.rotatephoto=Föteli umadräya
 undo.convertnamestotimes=Name ins Ziitstämple verwondlä
+undo.lookupsrtm=Höhendate vonem SRTM hole
 
 # Error messages
 error.save.dialogtitle=Fähle bim Speichere
@@ -558,6 +585,7 @@ error.jpegload.nofilesfound=Kei Dateie gfunde
 error.jpegload.nojpegsfound=Kei Jpegs gfunde
 error.jpegload.noexiffound=Kei EXIF Information gfunde
 error.jpegload.nogpsfound=Kei GPS Information gfunde
+error.jpegload.exifreadfailed=EXIF Uufruef isch fehlgschlage. Kei EXIF Infos könnet gläse werde\nohni nen interni oder extärni Bibliothek.
 error.gpsload.unknown=Unbekannts Fähler
 error.undofailed.title=Undo isch fehlgschlage worde
 error.undofailed.text=Operation kann nöd rückgängig gmacht werde
@@ -571,3 +599,4 @@ error.osmimage.dialogtitle=F
 error.osmimage.failed=Map Bildli könne nöd glade werde.  Gits ne Internet Verbindig?
 error.language.wrongfile=Die uusgewählti Datei scheint kei Sproch-Datei für Prune z'sii
 error.convertnamestotimes.nonames=Kei Namen han könnet verwondlet werde
+error.lookupsrtm.none=Kei Höhendate gfunde
index 47ccdc68496c989551d40bc9c9c8eab09584d5f6..d92a98a674282cf52415597a79dcfad224b4c0de 100644 (file)
@@ -3,32 +3,31 @@
 
 # Menu entries
 menu.file=File
-menu.file.open=Open file
 menu.file.addphotos=Add photos
 menu.file.save=Save
 menu.file.exit=Exit
 menu.track=Track
-menu.edit.undo=Undo
-menu.edit.clearundo=Clear undo list
-menu.edit.editpoint=Edit point
-menu.edit.deletepoint=Delete point
-menu.edit.deleterange=Delete range
-menu.edit.deletemarked=Delete marked points
-menu.edit.interpolate=Interpolate
-menu.edit.average=Average selection
-menu.edit.reverse=Reverse range
-menu.edit.mergetracksegments=Merge track segments
-menu.edit.rearrange=Rearrange waypoints
-menu.edit.rearrange.start=All to start of file
-menu.edit.rearrange.end=All to end of file
-menu.edit.rearrange.nearest=Each to nearest track point
-menu.edit.cutandmove=Cut and move selection
+menu.track.undo=Undo
+menu.track.clearundo=Clear undo list
+menu.track.deletemarked=Delete marked points
+menu.track.rearrange=Rearrange waypoints
+menu.track.rearrange.start=All to start of file
+menu.track.rearrange.end=All to end of file
+menu.track.rearrange.nearest=Each to nearest track point
 menu.range=Range
+menu.range.all=Select all
+menu.range.none=Select none
+menu.range.start=Set range start
+menu.range.end=Set range end
+menu.range.deleterange=Delete range
+menu.range.interpolate=Interpolate
+menu.range.average=Average selection
+menu.range.reverse=Reverse range
+menu.range.mergetracksegments=Merge track segments
+menu.range.cutandmove=Cut and move selection
 menu.point=Point
-menu.select.all=Select all
-menu.select.none=Select none
-menu.select.start=Set range start
-menu.select.end=Set range end
+menu.point.editpoint=Edit point
+menu.point.deletepoint=Delete point
 menu.photo=Photo
 menu.photo.saveexif=Save to Exif
 menu.photo.connect=Connect to point
@@ -42,6 +41,7 @@ menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Bing maps
 menu.settings=Settings
+menu.settings.onlinemode=Load maps from internet
 menu.help=Help
 # Popup menu for map
 menu.map.zoomin=Zoom in
@@ -67,12 +67,13 @@ altkey.menu.help=H
 shortcut.menu.file.open=O
 shortcut.menu.file.load=L
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=C
-shortcut.menu.select.all=A
+shortcut.menu.range.all=A
 shortcut.menu.help.help=H
 
 # Functions
+function.open=Open file
 function.loadfromgps=Load data from GPS
 function.sendtogps=Send data to GPS
 function.exportkml=Export KML
@@ -90,6 +91,7 @@ function.show3d=Three-D view
 function.distances=Distances
 function.fullrangedetails=Full range details
 function.getgpsies=Get Gpsies tracks
+function.lookupsrtm=Get altitudes from SRTM
 function.duplicatepoint=Duplicate point
 function.correlatephotos=Correlate photos
 function.rearrangephotos=Rearrange photos
@@ -106,6 +108,7 @@ function.showkeys=Show shortcut keys
 function.about=About Prune
 function.checkversion=Check for new version
 function.saveconfig=Save settings
+function.diskcache=Save maps to disk
 
 # Dialogs
 dialog.exit.confirm.title=Exit Prune
@@ -131,6 +134,7 @@ dialog.openoptions.deliminfo.records=records, with
 dialog.openoptions.deliminfo.fields=fields
 dialog.openoptions.deliminfo.norecords=No records
 dialog.openoptions.altitudeunits=Altitude units
+dialog.open.contentsdoubled=This file contains two copies of each point,\nonce as waypoints and once as track points.
 dialog.jpegload.subdirectories=Include subdirectories
 dialog.jpegload.loadjpegswithoutcoords=Include photos without coordinates
 dialog.jpegload.loadjpegsoutsidearea=Include photos outside current area
@@ -238,11 +242,14 @@ dialog.distances.column.to=To point
 dialog.distances.currentpoint=Current point
 dialog.distances.toofewpoints=This function needs waypoints in order to calculate the distances between them
 dialog.fullrangedetails.intro=Here are the details for the selected range
-dialog.setmapbg.mapnik=Mapnik (default)
-dialog.setmapbg.osma=Osma
-dialog.setmapbg.cyclemap=Cyclemap
-dialog.setmapbg.other=Other
-dialog.setmapbg.server=Server URL
+dialog.setmapbg.intro=Select one of the map sources, or add a new one
+dialog.addmapsource.title=Add new map source
+dialog.addmapsource.sourcename=Name of source
+dialog.addmapsource.layer1url=URL of first layer
+dialog.addmapsource.layer2url=Optional URL of second layer
+dialog.addmapsource.maxzoom=Maximum zoom level
+dialog.addmapsource.cloudstyle=Style number
+dialog.addmapsource.noname=Unnamed
 dialog.gpsies.column.name=Track name
 dialog.gpsies.column.length=Length
 dialog.gpsies.description=Description
@@ -304,6 +311,11 @@ dialog.about.systeminfo.povray=Povray installed
 dialog.about.systeminfo.exiftool=Exiftool installed
 dialog.about.systeminfo.gpsbabel=Gpsbabel installed
 dialog.about.systeminfo.gnuplot=Gnuplot installed
+dialog.about.systeminfo.exiflib=Exif library
+dialog.about.systeminfo.exiflib.internal=Internal
+dialog.about.systeminfo.exiflib.internal.failed=Internal (not found)
+dialog.about.systeminfo.exiflib.external=External
+dialog.about.systeminfo.exiflib.external.failed=External (not found)
 dialog.about.yes=Yes
 dialog.about.no=No
 dialog.about.credits=Credits
@@ -324,7 +336,7 @@ dialog.checkversion.releasedate1=This new version was released on
 dialog.checkversion.releasedate2=.
 dialog.checkversion.download=To download the new version, go to http://activityworkshop.net/software/prune/download.html.
 dialog.keys.intro=You can use the following shortcut keys instead of using the mouse
-dialog.keys.keylist=<table><tr><td>Arrow keys</td><td>Pan map left right, up, down</td></tr><tr><td>Ctrl + left, right arrow</td><td>Select previous or next point</td></tr><tr><td>Ctrl + up, down arrow</td><td>Zoom in or out</td></tr><tr><td>Del</td><td>Delete current point</td></tr></table>
+dialog.keys.keylist=<table><tr><td>Arrow keys</td><td>Pan map left right, up, down</td></tr><tr><td>Ctrl + left, right arrow</td><td>Select previous or next point</td></tr><tr><td>Ctrl + up, down arrow</td><td>Zoom in or out</td></tr><tr><td>Ctrl + PgUp, PgDown</td><td>Select previous, next segment</td></tr><tr><td>Ctrl + Home, End</td><td>Select first, last point</td></tr><tr><td>Del</td><td>Delete current point</td></tr></table>
 dialog.saveconfig.desc=The following settings can be saved to a configuration file :
 dialog.saveconfig.prune.trackdirectory=Track directory
 dialog.saveconfig.prune.photodirectory=Photo directory
@@ -337,13 +349,15 @@ dialog.saveconfig.prune.metricunits=Use metric units?
 dialog.saveconfig.prune.gnuplotpath=Path to gnuplot
 dialog.saveconfig.prune.gpsbabelpath=Path to gpsbabel
 dialog.saveconfig.prune.exiftoolpath=Path to exiftool
-dialog.saveconfig.prune.mapserverindex=Index of map server
-dialog.saveconfig.prune.mapserverurl=URL of map server
+dialog.saveconfig.prune.mapsource=Selected map source
+dialog.saveconfig.prune.mapsourcelist=Map sources
+dialog.saveconfig.prune.diskcache=Map cache
 dialog.saveconfig.prune.kmzimagewidth=KMZ image width
 dialog.saveconfig.prune.kmzimageheight=KMZ image height
 dialog.saveconfig.prune.colourscheme=Colour scheme
 dialog.saveconfig.prune.kmltrackcolour=KML track colour
 dialog.setpaths.intro=If you need to, you can choose the paths to the external applications:
+dialog.setpaths.found=Path found?
 dialog.addaltitude.noaltitudes=The selected range does not contain altitudes
 dialog.addaltitude.desc=Altitude offset to add
 dialog.setcolours.intro=Click on a colour patch to change the colour
@@ -364,6 +378,10 @@ dialog.setlanguage.secondintro=You need to save your settings and then<p>restart
 dialog.setlanguage.language=Language
 dialog.setlanguage.languagefile=Language file
 dialog.setlanguage.endmessage=Now save your settings and restart Prune\nfor the language change to take effect.
+dialog.diskcache.save=Save map images to disk
+dialog.diskcache.dir=Cache directory
+dialog.diskcache.createdir=Create directory
+dialog.diskcache.nocreate=Cache directory not created
 
 # 3d window
 dialog.3d.title=Prune Three-d view
@@ -400,6 +418,8 @@ confirm.correlate.multi=photos were correlated
 confirm.rotatephoto=photo rotated
 confirm.createpoint=point created
 confirm.running=Running ...
+confirm.lookupsrtm1=Found
+confirm.lookupsrtm2=altitude values
 
 # Buttons
 button.ok=OK
@@ -429,6 +449,8 @@ button.showwebpage=Show webpage
 button.check=Check
 button.resettodefaults=Reset to defaults
 button.browse=Browse...
+button.addnew=Add new
+button.delete=Delete
 
 # File types
 filetype.txt=TXT files
@@ -443,6 +465,7 @@ filetype.svg=SVG files
 # Display components
 display.nodata=No data loaded
 display.noaltitudes=Track data does not include altitudes
+display.notimestamps=Track data does not include timestamps
 details.trackdetails=Track details
 details.notrack=No track loaded
 details.track.points=Points
@@ -467,7 +490,8 @@ display.range.time.mins=m
 display.range.time.hours=h
 display.range.time.days=d
 details.range.avespeed=Ave speed
-details.range.avemovingspeed=Moving ave
+details.range.avemovingspeed=Moving average
+details.range.maxspeed=Maximum speed
 details.range.numsegments=Number of segments
 details.range.pace=Pace
 details.range.gradient=Gradient
@@ -548,6 +572,7 @@ undo.rearrangephotos=rearrange photos
 undo.rotatephoto=rotate photo
 undo.createpoint=create point
 undo.convertnamestotimes=convert names to times
+undo.lookupsrtm=lookup altitudes from SRTM
 
 # Error messages
 error.save.dialogtitle=Error saving data
@@ -571,6 +596,7 @@ error.jpegload.nofilesfound=No files found
 error.jpegload.nojpegsfound=No jpeg files found
 error.jpegload.noexiffound=No EXIF information found
 error.jpegload.nogpsfound=No GPS information found
+error.jpegload.exifreadfailed=Failed to read EXIF information. No EXIF information can be read\nwithout either an internal or external library.
 error.gpsload.unknown=Unknown error
 error.undofailed.title=Undo failed
 error.undofailed.text=Failed to undo operation
@@ -584,3 +610,4 @@ error.osmimage.dialogtitle=Error loading map images
 error.osmimage.failed=Failed to load map images. Please check internet connection.
 error.language.wrongfile=The selected file doesn't appear to be a language file for Prune
 error.convertnamestotimes.nonames=No names could be converted into times
+error.lookupsrtm.none=No altitude values found
index e610064ccb12233c91496da4991cc03b89e2aca7..a54ee1b2ecb4bad853899ec08635209d050574be 100644 (file)
@@ -3,34 +3,31 @@
 
 # Menu entries
 menu.file=Archivo
-menu.file.open=Abrir archivo
 menu.file.addphotos=Cargar fotos
 menu.file.save=Guardar
 menu.file.exit=Salir
-menu.edit=Editar
 menu.track=Track
-menu.edit.undo=Deshacer
-menu.edit.clearundo=Despejar la lista de deshacer
-menu.edit.editpoint=Editar punto
-menu.edit.deletepoint=Eliminar punto
-menu.edit.deleterange=Eliminar rango
-menu.edit.deletemarked=Eliminar puntos marcados
-menu.edit.interpolate=Interpolar
-menu.edit.average=Crear punto a la media del rango
-menu.edit.reverse=Invertir rango
-menu.edit.mergetracksegments=Unir los segmentos de track
-menu.edit.rearrange=Reorganizar waypoints
-menu.edit.rearrange.start=Volver al comienzo
-menu.edit.rearrange.end=Ir al final
-menu.edit.rearrange.nearest=Ir al m\u00e1s pr\u00f3ximo
-menu.edit.cutandmove=Cortar y mover selecci\u00f3n
-menu.select=Seleccionar
+menu.track.undo=Deshacer
+menu.track.clearundo=Despejar la lista de deshacer
+menu.track.deletemarked=Eliminar puntos marcados
+menu.track.rearrange=Reorganizar waypoints
+menu.track.rearrange.start=Volver al comienzo
+menu.track.rearrange.end=Ir al final
+menu.track.rearrange.nearest=Ir al m\u00e1s pr\u00f3ximo
 menu.range=Rango
+menu.range.all=Seleccionar todo
+menu.range.none=No seleccionar nada
+menu.range.start=Fijar comienzo
+menu.range.end=Fijar final
+menu.range.deleterange=Eliminar rango
+menu.range.interpolate=Interpolar
+menu.range.average=Crear punto a la media del rango
+menu.range.reverse=Invertir rango
+menu.range.mergetracksegments=Unir los segmentos de track
+menu.range.cutandmove=Cortar y mover selecci\u00f3n
 menu.point=Punto
-menu.select.all=Seleccionar todo
-menu.select.none=No seleccionar nada
-menu.select.start=Fijar comienzo
-menu.select.end=Fijar final
+menu.point.editpoint=Editar punto
+menu.point.deletepoint=Eliminar punto
 menu.photo=Foto
 menu.photo.saveexif=Guardar Exif
 menu.photo.connect=Conectar con punto
@@ -57,8 +54,6 @@ menu.map.showscalebar=Mostrar barra de escala
 
 # Alt keys for menus
 altkey.menu.file=A
-altkey.menu.edit=E
-altkey.menu.select=S
 altkey.menu.track=T
 altkey.menu.range=R
 altkey.menu.point=U
@@ -71,12 +66,13 @@ altkey.menu.help=Y
 shortcut.menu.file.open=A
 shortcut.menu.file.load=C
 shortcut.menu.file.save=G
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=C
-shortcut.menu.select.all=T
+shortcut.menu.range.all=T
 shortcut.menu.help.help=H
 
 # Functions
+function.open=Abrir archivo
 function.loadfromgps=Cargar datos del GPS
 function.sendtogps=Enviar datos al GPS
 function.exportkml=Exportar KML
@@ -214,8 +210,6 @@ dialog.addtimeoffset.minutes=Minutos
 dialog.addtimeoffset.notimestamps=No se puede a\u00f1adir tiempo de puesta a esta selecci\u00f3n si \u00e9sta no contiene ninguna informaci\u00f3n de "timestamp"
 dialog.findwaypoint.intro=Ingresar parte del nombre de "waypoint"
 dialog.findwaypoint.search=Buscar
-dialog.connect.title=Conectar foto
-dialog.connectphoto.clonepoint=Este punto ya tiene una foto.\n Quisiera usted hacer una copia de este?
 dialog.saveexif.title=Guardar Exif
 dialog.saveexif.intro=Seleccione fotos a guardar
 dialog.saveexif.nothingtosave=Coordenadas no modificadas, nada que guardar
@@ -243,9 +237,9 @@ dialog.distances.column.to=Al punto
 dialog.distances.currentpoint=Punto actual
 dialog.distances.toofewpoints=Esta funcion necesita "waypoints" para poder calcular las distancias entre ellos
 dialog.fullrangedetails.intro=Aqui estan los detalles para la selecci\u00f3n de rangos
-dialog.setmapbg.mapnik=Mapnik (predeterminado)
-dialog.setmapbg.other=Otro
-dialog.setmapbg.server=Direcci\u00f3n URL del servidor
+dialog.addmapsource.sourcename=Nombre de la fuente
+dialog.addmapsource.cloudstyle=N\u00famero del estilo
+dialog.addmapsource.noname=Innominada
 dialog.gpsies.column.name=Nombre del track
 dialog.gpsies.column.length=Distancia
 dialog.gpsies.description=Descripci\u00f3n
@@ -304,6 +298,11 @@ dialog.about.systeminfo.povray=Povray instalado
 dialog.about.systeminfo.exiftool=Exiftool instalado
 dialog.about.systeminfo.gpsbabel=Gpsbabel instalado
 dialog.about.systeminfo.gnuplot=Gnuplot instalado
+dialog.about.systeminfo.exiflib=Bibliotheca exif
+dialog.about.systeminfo.exiflib.internal=Interna
+dialog.about.systeminfo.exiflib.internal.failed=Interna (no encontrada)
+dialog.about.systeminfo.exiflib.external=Externa
+dialog.about.systeminfo.exiflib.external.failed=Externa (no encontrada)
 dialog.about.yes=Si
 dialog.about.no=No
 dialog.about.credits=Creditos
@@ -337,6 +336,8 @@ dialog.saveconfig.prune.gpsbabelpath=Camino a gpsbabel
 dialog.saveconfig.prune.exiftoolpath=Camino a exiftool
 dialog.saveconfig.prune.mapserverindex=\u00cdndice de mapa del servidor
 dialog.saveconfig.prune.mapserverurl=Direcci\u00f3n URL de mapa del servidor
+dialog.saveconfig.prune.mapsourcelist=Fuentes de cartas
+dialog.saveconfig.prune.diskcache=Directorio de cartas
 dialog.saveconfig.prune.kmzimagewidth=Ancho de im\u00e1genes en kmz
 dialog.saveconfig.prune.kmzimageheight=Alto de im\u00e1genes en kmz
 dialog.saveconfig.prune.colourscheme=Color de esquema
@@ -362,6 +363,9 @@ dialog.setlanguage.secondintro=Usted necesita salvar su configuraci\u00f3n y lue
 dialog.setlanguage.language=Lenguaje
 dialog.setlanguage.languagefile=Archivo de lenguaje
 dialog.setlanguage.endmessage=Ahora salve su configuraci\u00f3n y reinicie Prune\npara que los cambios tomen efecto.
+dialog.diskcache.save=Cargar cartas
+dialog.diskcache.dir=Directorio de cartas
+dialog.diskcache.createdir=Crear directorio
 
 # 3d window
 dialog.3d.title=Prune vista 3-D
@@ -423,6 +427,7 @@ button.guessfields=Adivinar campos
 button.showwebpage=Mostrar p\u00e1gina web
 button.check=Verificar
 button.resettodefaults=Restablecer valores a los predeterminados
+button.delete=Eliminar
 
 # File types
 filetype.txt=Archivos TXT
@@ -437,6 +442,7 @@ filetype.svg=Archivos SVG
 # Display components || These are all for the side panels showing point/range details
 display.nodata=Ning\u00fan dato cargado
 display.noaltitudes=Los datos del track no incluyen altitudes
+display.notimestamps=Los datos del track no incluyen tiempos
 details.trackdetails=Detalles del track
 details.notrack=Ning\u00fan track cargado
 details.track.points=Puntos
@@ -462,6 +468,7 @@ display.range.time.hours=h
 display.range.time.days=d
 details.range.avespeed=Velocidad media
 details.range.avemovingspeed=Moviendo promedio
+details.range.maxspeed=Velocidad m\u00e1xima
 details.range.numsegments=N\u00famero de segmentos
 details.range.gradient=Gradiente
 details.waypointsphotos.waypoints=Waypoints
@@ -534,8 +541,8 @@ undo.rearrangewaypoints=reordenar waypoints
 undo.connectphoto=conectar foto
 undo.disconnectphoto=desconectar foto
 undo.correlate=correlacionar fotos
-undo.rotatephoto=girar foto
 undo.createpoint=crear punto
+undo.rotatephoto=girar foto
 
 # Error messages
 error.save.dialogtitle=Fallo al guardar datos
index b5d9e276e1e499f51bb81c2b21e62315b888f1f8..dcbc3a7c65a6172c946f23026d24d0036e840895 100644 (file)
@@ -3,34 +3,31 @@
 
 # Menu entries
 menu.file=Fichier
-menu.file.open=Ouvrir fichier
 menu.file.addphotos=Ajouter photos
 menu.file.save=Enregistrer
 menu.file.exit=Quitter
-menu.edit=\u00c9dition
 menu.track=Trace
-menu.edit.undo=Annuler
-menu.edit.clearundo=Purger la liste d'annulation
-menu.edit.editpoint=Editer le point
-menu.edit.deletepoint=Supprimer le point
-menu.edit.deleterange=Supprimer l'\u00e9tendue
-menu.edit.deletemarked=Supprimer les points marqu\u00e9s
-menu.edit.interpolate=Interpoler
-menu.edit.average=Cr\u00e9er un point pour la s\u00e9lection
-menu.edit.reverse=Inverser l'\u00e9tendue
-menu.edit.mergetracksegments=Fusionner les segments de trace
-menu.edit.rearrange=R\u00e9arranger les waypoints
-menu.edit.rearrange.start=Tous au d\u00e9but du fichier
-menu.edit.rearrange.end=Tous \u00e0 la fin du fichier
-menu.edit.rearrange.nearest=Chacun au point de trace le plus proche
-menu.edit.cutandmove=Couper et bouger la s\u00e9lection
-menu.select=S\u00e9lectionner
+menu.track.undo=Annuler
+menu.track.clearundo=Purger la liste d'annulation
+menu.track.deletemarked=Supprimer les points marqu\u00e9s
+menu.track.rearrange=R\u00e9arranger les waypoints
+menu.track.rearrange.start=Tous au d\u00e9but du fichier
+menu.track.rearrange.end=Tous \u00e0 la fin du fichier
+menu.track.rearrange.nearest=Chacun au point de trace le plus proche
 menu.range=\u00c9tendue
+menu.range.all=Tout s\u00e9lectionner
+menu.range.none=Rien s\u00e9lectionner
+menu.range.start=D\u00e9finir le d\u00e9but de l'\u00e9tendue
+menu.range.end=D\u00e9finir la fin de l'\u00e9tendue
+menu.range.deleterange=Supprimer l'\u00e9tendue
+menu.range.interpolate=Interpoler
+menu.range.average=Cr\u00e9er un point pour la s\u00e9lection
+menu.range.reverse=Inverser l'\u00e9tendue
+menu.range.mergetracksegments=Fusionner les segments de trace
+menu.range.cutandmove=Couper et bouger la s\u00e9lection
 menu.point=Point
-menu.select.all=Tout s\u00e9lectionner
-menu.select.none=Rien s\u00e9lectionner
-menu.select.start=D\u00e9finir le d\u00e9but de l'\u00e9tendue
-menu.select.end=D\u00e9finir la fin de l'\u00e9tendue
+menu.point.editpoint=Editer le point
+menu.point.deletepoint=Supprimer le point
 menu.photo=Photo
 menu.photo.saveexif=Enregistrer dans les Exif
 menu.photo.connect=Relier au point
@@ -44,7 +41,7 @@ menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Yahoo maps
 menu.view.browser.bing=Cartes dans Bing
 menu.settings=Pr\u00e9f\u00e9rences
-menu.settings.showpace=Montrer allure dans les d\u00e9tails
+menu.settings.onlinemode=Charger une carte depuis internet
 menu.help=Aide
 # Popup menu for map
 menu.map.zoomin=Zoom avant
@@ -58,8 +55,6 @@ menu.map.showscalebar=Montrer l'echelle
 
 # Alt keys for menus
 altkey.menu.file=F
-altkey.menu.edit=E
-altkey.menu.select=S
 altkey.menu.track=T
 altkey.menu.range=E
 altkey.menu.point=P
@@ -72,14 +67,15 @@ altkey.menu.help=I
 shortcut.menu.file.open=O
 shortcut.menu.file.load=T
 shortcut.menu.file.save=E
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=C
-shortcut.menu.select.all=S
+shortcut.menu.range.all=S
 shortcut.menu.help.help=A
 
 # Functions
-function.loadfromgps=T\u00e9l\u00e9charger du GPS
-function.sendtogps=Envoyer au GPS
+function.open=Ouvrir fichier
+function.loadfromgps=T\u00e9l\u00e9charger donn\u00e9es du GPS
+function.sendtogps=Envoyer donn\u00e9es au GPS
 function.exportkml=Exporter en KML
 function.exportgpx=Exporter en GPX
 function.exportpov=Exporter en POV
@@ -98,6 +94,7 @@ function.setmapbg=D\u00e9finir le fond de carte
 function.setkmzimagesize=D\u00e9finir la taille de l'image KMZ
 function.setpaths=D\u00e9finir les chemins des programmes
 function.getgpsies=R\u00e9cup\u00e9rer les traces Gpsies
+function.lookupsrtm=R\u00e9cup\u00e9rer les altitudes depuis SRTM
 function.duplicatepoint=Duppliquer le point
 function.setcolours=R\u00e9gler les couleurs
 function.setlanguage=R\u00e9gler la langue
@@ -111,6 +108,7 @@ function.showkeys=Montrer les raccourcis clavier
 function.about=À propos de Prune
 function.checkversion=Chercher une mise \u00e0 jour
 function.saveconfig=Enregistrer les pr\u00e9f\u00e9rences
+function.diskcache=Enregistrer les cartes sur le disque
 
 # Dialogs
 dialog.exit.confirm.title=Quitter Prune
@@ -121,12 +119,12 @@ dialog.deletepoint.title=Effacer le point
 dialog.deletepoint.deletephoto=Effacer la photo attach\u00e9e \u00e0 ce point ?
 dialog.deletephoto.title=Effacer la photo
 dialog.deletephoto.deletepoint=Effacer le point attach\u00e9 \u00e0 cette photo ?
-dialog.openoptions.title=Ouvrir options
-dialog.openoptions.filesnippet=Extrait de fichier
+dialog.openoptions.title=Options d'ouverture
+dialog.openoptions.filesnippet=Extraire vers le fichier
 dialog.load.table.field=Champ
 dialog.load.table.datatype=Type de donn\u00e9e
 dialog.load.table.description=Description
-dialog.delimiter.label=S\u00e9parateur de texte
+dialog.delimiter.label=S\u00e9parateur de champ
 dialog.delimiter.comma=Virgule ,
 dialog.delimiter.tab=Tabulation
 dialog.delimiter.space=Espace
@@ -138,7 +136,7 @@ dialog.openoptions.deliminfo.norecords=Pas d'enregistrements
 dialog.openoptions.altitudeunits=Unit\u00e9s d'altitude
 dialog.jpegload.subdirectories=Inclure les sous-dossiers
 dialog.jpegload.loadjpegswithoutcoords=Inclure les photos sans coordonn\u00e9es
-dialog.jpegload.loadjpegsoutsidearea=Inclure des photos en dehors de l'endroit actuel
+dialog.jpegload.loadjpegsoutsidearea=Inclure des photos en dehors de la zone actuel
 dialog.jpegload.progress.title=Chargement des photos
 dialog.jpegload.progress=Veuillez patienter pendant la recherche des photos
 dialog.gpsload.nogpsbabel=Gpsbabel introuvable. Continuer ?
@@ -153,9 +151,9 @@ dialog.gpssend.trackname=Nom de trace
 dialog.saveoptions.title=Enregistrer le fichier
 dialog.save.fieldstosave=Champs \u00e0 enregistrer
 dialog.save.table.field=Champ
-dialog.save.table.hasdata=Poss\u00e8de une information
+dialog.save.table.hasdata=Contient une donn\u00e9e
 dialog.save.table.save=Enregistrer
-dialog.save.headerrow=Ent\u00eates
+dialog.save.headerrow=En-t\u00eates
 dialog.save.coordinateunits=Unit\u00e9s des coordonn\u00e9es
 dialog.save.altitudeunits=Unit\u00e9s d'altitude
 dialog.save.timestampformat=Format de l'heure
@@ -163,14 +161,14 @@ dialog.save.overwrite.title=Le fichier existe d\u00e9j\u00e0
 dialog.save.overwrite.text=Ce fichier existe d\u00e9j\u00e0. \u00cates-vous s\u00fbr de vouloir \u00e9craser ce fichier ?
 dialog.save.notypesselected=Aucun type de point n\u2019a \u00e9t\u00e9 s\u00e9lectionn\u00e9
 dialog.exportkml.text=Titre pour les donn\u00e9es
-dialog.exportkml.altitude=Absolues altitudes (pour aviation)
+dialog.exportkml.altitude=Altitudes absolues (pour l'aviation)
 dialog.exportkml.kmz=Compresser au format kmz
 dialog.exportkml.exportimages=Exporter les vignettes au format kmz
 dialog.exportkml.trackcolour=Couleur de la trace
 dialog.exportgpx.name=Nom
 dialog.exportgpx.desc=L\u00e9gende
 dialog.exportgpx.includetimestamps=Inclure l'heure pour chaque point
-dialog.exportgpx.copysource=Copier le XML source
+dialog.exportgpx.copysource=Copier la source xml
 dialog.exportpov.text=Entrez les param\u00e8tres pour l'export POV
 dialog.exportpov.font=Police
 dialog.exportpov.camerax=Cam\u00e9ra X
@@ -216,8 +214,6 @@ dialog.addtimeoffset.minutes=Minutes
 dialog.addtimeoffset.notimestamps=Ne peut pas d\u00e9caler l'heure; cette s\u00e9lection ne contient pas de donn\u00e9es d'heure
 dialog.findwaypoint.intro=Entrez une partie du nom de waypoint
 dialog.findwaypoint.search=Chercher
-dialog.connect.title=Lier la photo au point
-dialog.connectphoto.clonepoint=Ce point est d\u00e9j\u00e0 li\u00e9 \u00e0 une photo.\nVoulez-vous faire une copie de ce point ?
 dialog.saveexif.title=Enregistrer Exif
 dialog.saveexif.intro=S\u00e9lectionner les photos \u00e0 sauver \u00e0 l'aide des cases \u00e0 cocher
 dialog.saveexif.nothingtosave=Coordonn\u00e9es inchang\u00e9es, rien \u00e0 enregistrer
@@ -245,11 +241,14 @@ dialog.distances.column.to=Vers le point
 dialog.distances.currentpoint=Point courant
 dialog.distances.toofewpoints=Cette fonction a besoin de waypoints pour calculer les distances entre eux
 dialog.fullrangedetails.intro=Voici les d\u00e9tails pour l\u2019\u00e9tendue s\u00e9lectionn\u00e9e
-dialog.setmapbg.mapnik=Mapnik (d\u00e9faut)
-dialog.setmapbg.osma=Osma
-dialog.setmapbg.cyclemap=Cyclemap
-dialog.setmapbg.other=Autres
-dialog.setmapbg.server=URL du serveur
+dialog.setmapbg.intro=S\u00e9lectionnez une source de cartes, ou ajoutez-en une nouvelle
+dialog.addmapsource.title=Ajouter une nouvelle source de cartes
+dialog.addmapsource.sourcename=Nom de la source
+dialog.addmapsource.layer1url=URL de la premi\u00e8re couche
+dialog.addmapsource.layer2url=URL optionnelle de la deuxi\u00e8me couche
+dialog.addmapsource.maxzoom=Niveau de zoom maximum
+dialog.addmapsource.cloudstyle=Taille
+dialog.addmapsource.noname=Sans-titre
 dialog.gpsies.column.name=Nom de trace
 dialog.gpsies.column.length=Distance
 dialog.gpsies.description=Description
@@ -300,9 +299,9 @@ dialog.about.version=Version
 dialog.about.build=Build
 dialog.about.summarytext1=Prune est un programme pour charger, afficher et \u00e9diter des donn\u00e9es de r\u00e9cepteurs GPS.
 dialog.about.summarytext2=Distribu\u00e9 sous license Gnu GPL pour un usage et une am\u00e9lioration libres, ouverts et mondiaux.<br>La copie, la redistribution et la modification sont autoris\u00e9es et encourag\u00e9es<br>selon les conditions d\u00e9taill\u00e9es dans le fichier <code>license.txt</code> inclus.
-dialog.about.summarytext3=Consultez la page <code style``=``"font-weight:bold">http://activityworkshop.net/</code> pour plus de d\u00e9tails et des manuels utilisateur.
+dialog.about.summarytext3=Consultez la page <code style="font-weight:bold">http://activityworkshop.net/</code> pour plus de d\u00e9tails et des manuels utilisateur.
 dialog.about.languages=Langues disponibles
-dialog.about.translatedby=Texte en fran\u00e7ais par Petrovsk et theYinYeti.
+dialog.about.translatedby=Texte en fran\u00e7ais par Petrovsk, theYinYeti et R\u00e9mi.
 dialog.about.systeminfo=Info Syst\u00e8me
 dialog.about.systeminfo.os=Syst\u00e8me d'exploitation
 dialog.about.systeminfo.java=Java Runtime
@@ -311,6 +310,11 @@ dialog.about.systeminfo.povray=Povray install\u00e9
 dialog.about.systeminfo.exiftool=Exiftool install\u00e9
 dialog.about.systeminfo.gpsbabel=Gpsbabel install\u00e9
 dialog.about.systeminfo.gnuplot=Gnuplot install\u00e9
+dialog.about.systeminfo.exiflib=Librairie Exif
+dialog.about.systeminfo.exiflib.internal=Interne
+dialog.about.systeminfo.exiflib.internal.failed=Interne (non-trouv\u00e9)
+dialog.about.systeminfo.exiflib.external=Externe
+dialog.about.systeminfo.exiflib.external.failed=Externe (non-trouv\u00e9)
 dialog.about.yes=Oui
 dialog.about.no=Non
 dialog.about.credits=Cr\u00e9dits
@@ -340,18 +344,21 @@ dialog.saveconfig.prune.languagefile=Fichier de langue
 dialog.saveconfig.prune.gpsdevice=Chemin du p\u00e9riph\u00e9rique GPS
 dialog.saveconfig.prune.gpsformat=Format GPS
 dialog.saveconfig.prune.povrayfont=Police povray
-dialog.saveconfig.prune.metricunits=Utiliser le syst\u00e8me m\u00e9trique?
+dialog.saveconfig.prune.metricunits=Utiliser le syst\u00e8me m\u00e9trique ?
 dialog.saveconfig.prune.gnuplotpath=Chemin gnuplot
 dialog.saveconfig.prune.gpsbabelpath=Chemin gpsbabel
 dialog.saveconfig.prune.exiftoolpath=Chemin exiftool
 dialog.saveconfig.prune.mapserverindex=Index du serveur de carte
 dialog.saveconfig.prune.mapserverurl=URL du serveur de carte
-dialog.saveconfig.prune.showpace=Montrer l'allure
+dialog.saveconfig.prune.mapsource=Carte source s\u00e9lectionn\u00e9e
+dialog.saveconfig.prune.mapsourcelist=Sources de cartes
+dialog.saveconfig.prune.diskcache=Cache de carte
 dialog.saveconfig.prune.kmzimagewidth=Largeur de l'image KMZ
 dialog.saveconfig.prune.kmzimageheight=Hauteur de l'image KMZ
 dialog.saveconfig.prune.colourscheme=Mod\u00e8le de couleurs
 dialog.saveconfig.prune.kmltrackcolour=Couleur de la trace KML
 dialog.setpaths.intro=Si vous le souhaitez, vous pouvez d\u00e9finir les chemins des applications externes:
+dialog.setpaths.found=Chemin trouv\u00e9 ?
 dialog.addaltitude.noaltitudes=L'\u00e9tendue s\u00e9lectionn\u00e9e de contient pas d'altitudes
 dialog.addaltitude.desc=D\u00e9callage d'altitude \u00e0 ajouter
 dialog.setcolours.intro=Cliquez sur une couleur pour la changer
@@ -367,8 +374,15 @@ dialog.colourchooser.title=Choisissez la couleur
 dialog.colourchooser.red=Rouge
 dialog.colourchooser.green=Vert
 dialog.colourchooser.blue=Bleu
+dialog.setlanguage.firstintro=Vous pouvez s\u00e9lectionner l'une des langues disponibles,<p> ou bien un fichier de langue \u00e0 utiliser.
+dialog.setlanguage.secondintro=Vous devez sauvegarder vos param\u00e8tres puis<p>red\u00e9marrer Prune pour changer de langue.
 dialog.setlanguage.language=Langue
 dialog.setlanguage.languagefile=Fichier de langue
+dialog.setlanguage.endmessage=Enregistrez vos r\u00e9glages et red\u00e9marrez Prune\npour que le changement de langue soit effectif.
+dialog.diskcache.save=Enregistrer les images de carte sur le disque
+dialog.diskcache.dir=R\u00e9pertoire cache
+dialog.diskcache.createdir=Cr\u00e9er r\u00e9pertoire
+dialog.diskcache.nocreate=Le r\u00e9pertoire cache n'est pas cr\u00e9\u00e9
 
 # 3d window
 dialog.3d.title=Vue 3D de Prune
@@ -392,7 +406,7 @@ confirm.rearrangewaypoints=Waypoints r\u00e9arrang\u00e9s
 confirm.rearrangephotos=Photos r\u00e9arrang\u00e9es
 confirm.cutandmove=S\u00e9lection d\u00e9plac\u00e9e
 confirm.convertnamestotimes=Noms de waypoints convertis
-confirm.saveexif.ok1=Enregistrement de
+confirm.saveexif.ok1=Enregistr\u00e9
 confirm.saveexif.ok2=fichiers photo
 confirm.undo.single=op\u00e9ration annul\u00e9e
 confirm.undo.multi=op\u00e9rations annul\u00e9es
@@ -405,6 +419,8 @@ confirm.correlate.multi=photos ont \u00e9t\u00e9 corr\u00e9l\u00e9es
 confirm.createpoint=Point cr\u00e9\u00e9
 confirm.rotatephoto=Photo tourn\u00e9e
 confirm.running=En cours...
+confirm.lookupsrtm1=Trouv\u00e9
+confirm.lookupsrtm2=valeurs d'altitude
 
 # Buttons || These are all the texts for buttons
 button.ok=OK
@@ -433,6 +449,9 @@ button.guessfields=Deviner les champs
 button.showwebpage=Montrer page web
 button.check=V\u00e9rifier
 button.resettodefaults=Revenir aux valeurs par d\u00e9faut
+button.browse=Naviguer...
+button.addnew=Ajouter nouveau...
+button.delete=Supprimer
 
 # File types
 filetype.txt=Fichiers TXT
@@ -447,6 +466,7 @@ filetype.svg=Fichiers SVG
 # Display components || These are all for the side panels showing point/range details
 display.nodata=Pas de donn\u00e9es charg\u00e9es
 display.noaltitudes=La trace ne comporte pas d'information d'altitude
+display.notimestamps=La trace ne comporte pas d'information de temps
 details.trackdetails=D\u00e9tails de la trace
 details.notrack=Pas de trace charg\u00e9e
 details.track.points=Points
@@ -472,6 +492,7 @@ display.range.time.hours=h
 display.range.time.days=j
 details.range.avespeed=Vitesse moyenne
 details.range.avemovingspeed=Moyenne continue
+details.range.maxspeed=Vitesse maximum
 details.range.numsegments=Nombre de segments
 details.range.pace=Allure
 details.range.gradient=Pente
@@ -552,6 +573,7 @@ undo.rearrangephotos=R\u00e9arranger les photos
 undo.createpoint=ajouter un point
 undo.rotatephoto=Tourner la photo
 undo.convertnamestotimes=Convertir les noms en points
+undo.lookupsrtm=Rechercher les altitudes depuis SRTM
 
 # Error messages
 error.save.dialogtitle=Erreur \u00e0 l'enregistrement des donn\u00e9es
@@ -575,6 +597,7 @@ error.jpegload.nofilesfound=Aucun fichier trouv\u00e9
 error.jpegload.nojpegsfound=Aucun fichier jpeg trouv\u00e9
 error.jpegload.noexiffound=Aucune information EXIF trouv\u00e9e
 error.jpegload.nogpsfound=Aucune information GPS trouv\u00e9e
+error.jpegload.exifreadfailed=Information EXIF illisible. Aucune information EXIF ne peut \u00eatre lue\nsans une librairie interne ou externe.
 error.gpsload.unknown=Erreur inconnue
 error.undofailed.title=Echec de l'annulation
 error.undofailed.text=Echec de l'op\u00e9ration d'annulation
@@ -586,3 +609,6 @@ error.3d=Un probl\u00e8me est survenu avec l'affichage 3D
 error.readme.notfound=Fichier Lisez-moi introuvable
 error.osmimage.dialogtitle=Erreur au chargement des portions de cartes
 error.osmimage.failed=Erreur du chargement des portions de cartes. V\u00e9rifiez votre connexion internet.
+error.language.wrongfile=Le fichier s\u00e9lectionn\u00e9 n'est pas un fichier de langue pour Prune
+error.convertnamestotimes.nonames=Aucun nom n'a pu \u00eatre converti en horaire
+error.lookupsrtm.none=Aucune valeur d'altitude trouv\u00e9e
index d76fa2e1ae845757c107c8d37cadfef088a484f6..42e2b3762e090c46e6c12726817ee0120b085895 100644 (file)
@@ -3,22 +3,18 @@
 
 # Menu entries
 menu.file=Berkas
-menu.file.open=Buka
 menu.file.addphotos=Muat foto
 menu.file.save=Simpan
 menu.file.exit=Keluar
-#menu.edit=Ubah
 menu.track=Track
-menu.edit.undo=Batal
-
-menu.edit.editpoint=Perbaiki titik
-menu.edit.deletepoint=Hapus titik
-menu.edit.deleterange=Hapus jarak
-#menu.select=Pilih
+menu.track.undo=Batal
+menu.point.editpoint=Perbaiki titik
+menu.point.deletepoint=Hapus titik
+menu.range.deleterange=Hapus jarak
 menu.range=Jangkauan
 menu.point=Titik
-menu.select.all=Pilih semua
-menu.select.none=Tidak memilih
+menu.range.all=Pilih semua
+menu.range.none=Tidak memilih
 menu.photo=Foto
 menu.photo.saveexif=Simpan ke Exif
 menu.photo.connect=Hubungkan ke titik
@@ -37,8 +33,6 @@ menu.map.showmap=Tampilkan peta
 
 # Alt keys for menus
 altkey.menu.file=B
-#altkey.menu.edit=U
-#altkey.menu.select=P
 altkey.menu.track=T
 altkey.menu.range=J
 altkey.menu.point=K
@@ -51,12 +45,13 @@ altkey.menu.help=N
 shortcut.menu.file.open=B
 shortcut.menu.file.load=M
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=P
-shortcut.menu.select.all=-
+shortcut.menu.range.all=-
 shortcut.menu.help.help=-
 
 # Functions
+function.open=Buka
 function.loadfromgps=Muat data dari GPS
 function.sendtogps=Kirim data ke GPS
 function.exportkml=Ekspor KML
@@ -64,12 +59,10 @@ function.exportgpx=Ekspor GPX
 function.exportpov=Ekspor POV
 function.editwaypointname=Perbaiki Nama waypoint
 function.compress=Padatkan jalur
-
 function.findwaypoint=Menemukan waypoint
 function.charts=Grafik
 function.show3d=Lihat tiga-D
 function.distances=Jarak
-
 function.correlatephotos=Korelasikan foto
 function.help=Bantuan
 function.about=Tentang Prune
index 0eb5179b41ddede3c80b116709a179b84dcf6876..0801cafe20b75a63ddd8ff937110b307ca186ad7 100644 (file)
@@ -3,34 +3,31 @@
 
 # Menu entries
 menu.file=File
-menu.file.open=Apri file
 menu.file.addphotos=Aggiungi foto
 menu.file.save=Salva
 menu.file.exit=Esci
-menu.edit=Edita
 menu.track=Traccia
-menu.edit.undo=Annulla
-menu.edit.clearundo=Cancella lista ultime modifiche
-menu.edit.editpoint=Edita punto
-menu.edit.deletepoint=Cancella punto
-menu.edit.deleterange=Cancella la serie
-menu.edit.deletemarked=Cancella punti marcati
-menu.edit.interpolate=Interpola
-menu.edit.average=Crea punto medio della selezione
-menu.edit.reverse=Inverti la serie
-menu.edit.mergetracksegments=Unisci segmenti traccia
-menu.edit.rearrange=Riorganizza waypoint
-menu.edit.rearrange.start=Tutti all'inizio del file
-menu.edit.rearrange.end=Tutti alla fine del file
-menu.edit.rearrange.nearest=Sul punto pi\u00f9 vicino
-menu.edit.cutandmove=Taglia e muovi la selezione
-menu.select=Seleziona
+menu.track.undo=Annulla
+menu.track.clearundo=Cancella lista ultime modifiche
+menu.point.editpoint=Edita punto
+menu.point.deletepoint=Cancella punto
+menu.range.deleterange=Cancella la serie
+menu.track.deletemarked=Cancella punti marcati
+menu.range.interpolate=Interpola
+menu.range.average=Crea punto medio della selezione
+menu.range.reverse=Inverti la serie
+menu.range.mergetracksegments=Unisci segmenti traccia
+menu.track.rearrange=Riorganizza waypoint
+menu.track.rearrange.start=Tutti all'inizio del file
+menu.track.rearrange.end=Tutti alla fine del file
+menu.track.rearrange.nearest=Sul punto pi\u00f9 vicino
+menu.range.cutandmove=Taglia e muovi la selezione
 menu.range=Serie
 menu.point=Punto
-menu.select.all=Seleziona tutto
-menu.select.none=Deseleziona tutto
-menu.select.start=Imposta inizio serie
-menu.select.end=Imposta fine serie
+menu.range.all=Seleziona tutto
+menu.range.none=Deseleziona tutto
+menu.range.start=Imposta inizio serie
+menu.range.end=Imposta fine serie
 menu.photo=Foto
 menu.photo.saveexif=Salva su Exif
 menu.photo.connect=Collega al punto
@@ -44,7 +41,6 @@ menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=mappe Yahoo
 menu.view.browser.bing=mappe Bing
 menu.settings=Preferenze
-menu.settings.showpace=Mostra passo nel display serie
 menu.help=Aiuto
 # Popup menu for map
 menu.map.zoomin=Zoom +
@@ -58,8 +54,6 @@ menu.map.showscalebar=Mostra scala
 
 # Alt keys for menus
 altkey.menu.file=F
-altkey.menu.edit=E
-altkey.menu.select=S
 altkey.menu.track=T
 altkey.menu.range=S
 altkey.menu.point=P
@@ -72,12 +66,13 @@ altkey.menu.help=A
 shortcut.menu.file.open=A
 shortcut.menu.file.load=C
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=C
-shortcut.menu.select.all=T
+shortcut.menu.range.all=T
 shortcut.menu.help.help=H
 
 # Functions
+function.open=Apri file
 function.loadfromgps=Carica dati da GPS
 function.sendtogps=Invia dati al GPS
 function.exportkml=Esporta in KML
@@ -201,8 +196,6 @@ dialog.addtimeoffset.minutes=Minuti
 dialog.addtimeoffset.notimestamps=Non posso aggiungere uno scarto temporale a questa selezione perch\u00e9 non contiene informazioni temporali
 dialog.findwaypoint.intro=Inserisci parte del nome del waypoint
 dialog.findwaypoint.search=Cerca
-dialog.connect.title=Collega la foto al punto
-dialog.connectphoto.clonepoint=Questo punto ha gi\u00e0 una foto collegata.\nVuoi fare una copia del punto?
 dialog.saveexif.title=Salva Exif
 dialog.saveexif.intro=Seleziona le foto da salvare usando le caselle di spunta
 dialog.saveexif.nothingtosave=Le coordinate non sono cambiate, niente da registrare
@@ -318,7 +311,6 @@ dialog.saveconfig.prune.gpsbabelpath=Path gpsbabel
 dialog.saveconfig.prune.exiftoolpath=Path exiftool
 dialog.saveconfig.prune.mapserverindex=Indice server mappe
 dialog.saveconfig.prune.mapserverurl=URL del server mappe
-dialog.saveconfig.prune.showpace=Mostra passo
 dialog.saveconfig.prune.kmzimagewidth=larghezza immagine KMZ
 dialog.saveconfig.prune.kmzimageheight=altezza immagine KMZ
 dialog.setpaths.intro=Se necessario, puoi indicare il percorso delle applicazioni esterne:
index a54fa2ef9046cd9ea35b3b0d36167e38aea34083..ee54e3dbd2aa592d6e9f49494b530790905be842 100644 (file)
@@ -3,34 +3,31 @@
 
 # Menu entries
 menu.file=\u30d5\u30a1\u30a4\u30eb
-menu.file.open=\u30d5\u30a1\u30a4\u30eb\u3092\u958b\u304f
 menu.file.addphotos=\u5199\u771f\u3092\u8ffd\u52a0
 menu.file.save=\u4fdd\u5b58
 menu.file.exit=\u7d42\u4e86
-menu.edit=\u7de8\u96c6
 menu.track=\u30c8\u30e9\u30c3\u30af
-menu.edit.undo=\u30a2\u30f3\u30c9\u30a5
-menu.edit.clearundo=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
-menu.edit.editpoint=\u70b9\u3092\u7de8\u96c6
-menu.edit.deletepoint=\u70b9\u3092\u524a\u9664
-menu.edit.deleterange=\u7bc4\u56f2\u3092\u524a\u9664
-menu.edit.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
-menu.edit.interpolate=\u88dc\u5b8c
-menu.edit.average=\u9078\u629e\u7bc4\u56f2\u3092\u5e73\u5747\u5316
-menu.edit.reverse=\u7bc4\u56f2\u3092\u53cd\u8ee2
-menu.edit.mergetracksegments=\u30c8\u30e9\u30c3\u30af\u30bb\u30b0\u30e1\u30f3\u30c8\u3092\u7d71\u5408
-menu.edit.rearrange=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u4e26\u3079\u66ff\u3048
-menu.edit.rearrange.start=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u59cb\u70b9\u306b
-menu.edit.rearrange.end=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u7d42\u70b9\u306b
-menu.edit.rearrange.nearest=\u305d\u308c\u305e\u308c\u3092\u6700\u8fd1\u306e\u30c8\u30e9\u30c3\u30af\u30dd\u30a4\u30f3\u30c8\u306b
-menu.edit.cutandmove=\u9078\u629e\u7bc4\u56f2\u3092\u79fb\u52d5
-menu.select=\u9078\u629e
+menu.track.undo=\u30a2\u30f3\u30c9\u30a5
+menu.track.clearundo=\u30a2\u30f3\u30c9\u30a5\u30ea\u30b9\u30c8\u3092\u7a7a\u306b\u3059\u308b
+menu.point.editpoint=\u70b9\u3092\u7de8\u96c6
+menu.point.deletepoint=\u70b9\u3092\u524a\u9664
+menu.range.deleterange=\u7bc4\u56f2\u3092\u524a\u9664
+menu.track.deletemarked=\u5370\u306e\u4ed8\u3044\u305f\u70b9\u3092\u524a\u9664
+menu.range.interpolate=\u88dc\u5b8c
+menu.range.average=\u9078\u629e\u7bc4\u56f2\u3092\u5e73\u5747\u5316
+menu.range.reverse=\u7bc4\u56f2\u3092\u53cd\u8ee2
+menu.range.mergetracksegments=\u30c8\u30e9\u30c3\u30af\u30bb\u30b0\u30e1\u30f3\u30c8\u3092\u7d71\u5408
+menu.track.rearrange=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u4e26\u3079\u66ff\u3048
+menu.track.rearrange.start=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u59cb\u70b9\u306b
+menu.track.rearrange.end=\u5168\u3066\u3092\u30d5\u30a1\u30a4\u30eb\u306e\u7d42\u70b9\u306b
+menu.track.rearrange.nearest=\u305d\u308c\u305e\u308c\u3092\u6700\u8fd1\u306e\u30c8\u30e9\u30c3\u30af\u30dd\u30a4\u30f3\u30c8\u306b
+menu.range.cutandmove=\u9078\u629e\u7bc4\u56f2\u3092\u79fb\u52d5
 menu.range=\u7bc4\u56f2
 menu.point=\u70b9
-menu.select.all=\u5168\u3066\u9078\u629e
-menu.select.none=\u9078\u629e\u89e3\u9664
-menu.select.start=\u958b\u59cb\u70b9\u3092\u7f6e\u304f
-menu.select.end=\u7d42\u4e86\u70b9\u3092\u7f6e\u304f
+menu.range.all=\u5168\u3066\u9078\u629e
+menu.range.none=\u9078\u629e\u89e3\u9664
+menu.range.start=\u958b\u59cb\u70b9\u3092\u7f6e\u304f
+menu.range.end=\u7d42\u4e86\u70b9\u3092\u7f6e\u304f
 menu.photo=\u5199\u771f
 menu.photo.saveexif=Exif\u306b\u4fdd\u5b58
 menu.photo.connect=\u70b9\u306b\u63a5\u7d9a
@@ -44,7 +41,6 @@ menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Yahoo \u5730\u56f3
 menu.view.browser.bing=Bing \u5730\u56f3
 menu.settings=\u8a2d\u5b9a
-menu.settings.showpace=\u8868\u793a\u7bc4\u56f2\u306e\u901f\u5ea6\u3092\u8868\u793a
 menu.help=\u30d8\u30eb\u30d7
 # Popup menu for map
 menu.map.zoomin=\u62e1\u5927
@@ -57,6 +53,7 @@ menu.map.showmap=\u5730\u56f3\u3092\u8868\u793a
 menu.map.showscalebar=\u7e2e\u5c3a\u8868\u793a
 
 # Functions
+function.open=\u30d5\u30a1\u30a4\u30eb\u3092\u958b\u304f
 function.loadfromgps=GPS\u304b\u3089\u30c7\u30fc\u30bf\u3092\u8aad\u3080
 function.sendtogps=GPS\u3078\u4fdd\u5b58
 function.exportkml=KML\u306b\u30a8\u30af\u30b9\u30dd\u30fc\u30c8
@@ -195,8 +192,6 @@ dialog.addtimeoffset.minutes=\u5206
 dialog.addtimeoffset.notimestamps=\u3053\u306e\u9078\u629e\u7bc4\u56f2\u306f\u30bf\u30a4\u30e0\u30b9\u30bf\u30f3\u30d7\u3092\u6301\u3063\u3066\u306a\u3044\u306e\u3067\u3001\u504f\u4f4d\u3092\u8db3\u305b\u307e\u305b\u3093\u3002
 dialog.findwaypoint.intro=\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u540d\u306e\u4e00\u90e8\u3092\u5165\u529b
 dialog.findwaypoint.search=\u691c\u7d22
-dialog.connect.title=\u70b9\u306b\u5199\u771f\u3092\u63a5\u7d9a
-dialog.connectphoto.clonepoint=\u3053\u306e\u70b9\u306f\u65e2\u306b\u5199\u771f\u3092\u6301\u3063\u3066\u307e\u3059\u3002\n\u30a6\u30a7\u30a4\u30dd\u30a4\u30f3\u30c8\u3092\u30b3\u30d4\u30fc\u3057\u307e\u3059\u304b\uff1f
 dialog.saveexif.title=EXIF\u3092\u4fdd\u5b58
 dialog.saveexif.intro=\u30c1\u30a7\u30c3\u30af\u30dc\u30c3\u30af\u30b9\u3092\u4f7f\u3063\u3066\u3001\u4fdd\u5b58\u3059\u308b\u5199\u771f\u3092\u9078\u629e\u3057\u3066\u304f\u3060\u3055\u3044\u3002
 dialog.saveexif.nothingtosave=\u5ea7\u6a19\u60c5\u5831\u306f\u7121\u5909\u66f4\u3067\u3059\u3002\u4fdd\u5b58\u3059\u308b\u3082\u306e\u306f\u3042\u308a\u307e\u305b\u3093\u3002
@@ -325,7 +320,6 @@ dialog.saveconfig.prune.gpsbabelpath=gpsbabel\u3078\u306e\u30d1\u30b9
 dialog.saveconfig.prune.exiftoolpath=exiftool\u3078\u306e\u30d1\u30b9
 dialog.saveconfig.prune.mapserverindex=\u80cc\u666f\u5730\u56f3\u30b5\u30fc\u30d0\u30fc\u306e\u7d22\u5f15(1-4)
 dialog.saveconfig.prune.mapserverurl=\u5730\u56f3\u30b5\u30fc\u30d0\u30fc\u306eURL
-dialog.saveconfig.prune.showpace=\u30da\u30fc\u30b9\u3092\u8868\u793a
 dialog.saveconfig.prune.kmzimagewidth=KML \u753b\u50cf\u5e45
 dialog.saveconfig.prune.kmzimageheight=KML \u753b\u50cf\u9ad8
 dialog.saveconfig.prune.colourscheme=\u8272\u306e\u30b9\u30ad\u30fc\u30e0
index c731f843750ef072cb7b8bdcc8be6bf23e85790a..b0456302544d7f7697776dffa447f5f71a25a1c0 100644 (file)
@@ -3,32 +3,31 @@
 
 # Menu entries
 menu.file=Plik
-menu.file.open=Otw\u00f3rz
 menu.file.addphotos=Dodaj zdj\u0119cia
 menu.file.save=Zapisz
 menu.file.exit=Zako\u0144cz
 menu.track=\u015acie\u017cka
-menu.edit.undo=Cofnij
-menu.edit.clearundo=Wyczy\u015b\u0107 list\u0119 zmian
-menu.edit.editpoint=Edytuj punkt
-menu.edit.deletepoint=Usu\u0144 punkt
-menu.edit.deleterange=Usu\u0144 zakres
-menu.edit.deletemarked=Usu\u0144 zaznaczone punkty
-menu.edit.interpolate=Wstaw pomi\u0119dzy
-menu.edit.average=U\u015brednij zaznaczenie
-menu.edit.reverse=Odwr\u00f3\u0107 zakres
-menu.edit.mergetracksegments=Po\u0142\u0105cz fragmenty \u015bcie\u017cek
-menu.edit.rearrange=Zmie\u0144 kolejno\u015b\u0107 punkt\u00f3w po\u015brednich
-menu.edit.rearrange.start=Wszystkie na pocz\u0105tek \u015bcie\u017cki
-menu.edit.rearrange.end=Wszystkie na koniec \u015bcie\u017cki
-menu.edit.rearrange.nearest=Do najbli\u017cszego punktu
-menu.edit.cutandmove=Wytnij i przesu\u0144 zaznaczenie
+menu.track.undo=Cofnij
+menu.track.clearundo=Wyczy\u015b\u0107 list\u0119 zmian
+menu.track.deletemarked=Usu\u0144 zaznaczone punkty
+menu.track.rearrange=Zmie\u0144 kolejno\u015b\u0107 punkt\u00f3w po\u015brednich
+menu.track.rearrange.start=Wszystkie na pocz\u0105tek \u015bcie\u017cki
+menu.track.rearrange.end=Wszystkie na koniec \u015bcie\u017cki
+menu.track.rearrange.nearest=Do najbli\u017cszego punktu
 menu.range=Zakres
+menu.range.all=Zaznacz wszystko
+menu.range.none=Usu\u0144 zaznaczenie
+menu.range.start=Zaznacz pocz\u0105tek zakresu
+menu.range.end=Zaznacz koniec zakresu
+menu.range.deleterange=Usu\u0144 zakres
+menu.range.interpolate=Wstaw pomi\u0119dzy
+menu.range.average=U\u015brednij zaznaczenie
+menu.range.reverse=Odwr\u00f3\u0107 zakres
+menu.range.mergetracksegments=Po\u0142\u0105cz fragmenty \u015bcie\u017cek
+menu.range.cutandmove=Wytnij i przesu\u0144 zaznaczenie
 menu.point=Punkt
-menu.select.all=Zaznacz wszystko
-menu.select.none=Usu\u0144 zaznaczenie
-menu.select.start=Zaznacz pocz\u0105tek zakresu
-menu.select.end=Zaznacz koniec zakresu
+menu.point.editpoint=Edytuj punkt
+menu.point.deletepoint=Usu\u0144 punkt
 menu.photo=Zdj\u0119cie
 menu.photo.saveexif=Zapisz Exif
 menu.photo.connect=Przy\u0142\u0105cz do punktu
@@ -42,6 +41,7 @@ menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Mapy Yahoo
 menu.view.browser.bing=Mapy Bing
 menu.settings=Ustawienia
+menu.settings.onlinemode=\u0141aduj mapy z sieci
 menu.help=Pomoc
 # Popup menu for map
 menu.map.zoomin=Powi\u0119ksz
@@ -67,12 +67,13 @@ altkey.menu.help=M
 shortcut.menu.file.open=O
 shortcut.menu.file.load=L
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=C
-shortcut.menu.select.all=A
+shortcut.menu.range.all=A
 shortcut.menu.help.help=H
 
 # Functions
+function.open=Otw\u00f3rz
 function.loadfromgps=\u0141aduj z GPS
 function.sendtogps=Wy\u015blij dane do urz\u0105dzenia GPS
 function.exportkml=Eksportuj KML
@@ -93,6 +94,7 @@ function.setmapbg=Wybierz map\u0119 t\u0142a
 function.setkmzimagesize=Ustaw rozmiar zdj\u0119\u0107 w KMZ
 function.setpaths=Ustaw \u015bcie\u017cki do program\u00f3w
 function.getgpsies=Pobierz \u015bcie\u017cki z Gpsies
+function.lookupsrtm=Pobierz wysoko\u015bci z SRTM
 function.duplicatepoint=Duplikuj plik
 function.setcolours=Ustaw kolory
 function.setlanguage=Zmie\u0144 j\u0119zyk
@@ -106,6 +108,7 @@ function.showkeys=Poka\u017c klawisze skr\u00f3tu
 function.about=O Prune
 function.checkversion=Sprawd\u017a czy jest nowa wersja
 function.saveconfig=Zapisz ustawienia
+function.diskcache=Zapisz mapy na dysk
 
 # Dialogs
 dialog.exit.confirm.title=Zako\u0144cz Prune
@@ -118,6 +121,7 @@ dialog.deletephoto.title=Usu\u0144 zdj\u0119cie
 dialog.deletephoto.deletepoint=Usun\u0105\u0107 punkt do\u0142\u0105czony do tego zdj\u0119cia?
 dialog.openoptions.title=Otw\u00f3rz opcje
 dialog.openoptions.filesnippet=Fragment z pliku
+dialog.open.contentsdoubled=Ten plik zawiera dwie kopie ka\u017cdego punktu.\nRaz jako punkt po\u015bredni, a raz jako punkt \u015bcie\u017cki.
 dialog.load.table.field=Pole
 dialog.load.table.datatype=Typ danych
 dialog.load.table.description=Opis
@@ -238,11 +242,14 @@ dialog.distances.column.to=Do punktu
 dialog.distances.currentpoint=Wybrany punkt
 dialog.distances.toofewpoints=Ta funkcja wymaga przynajmniej dw\u00f3ch punkt\u00f3w po\u015brednich, aby mo\u017cna by\u0142o obliczy\u0107 odleg\u0142o\u015bci
 dialog.fullrangedetails.intro=Szczeg\u00f3\u0142y wybranego zakresu
-dialog.setmapbg.mapnik=Mapnik (domy\u015blny)
-dialog.setmapbg.osma=Osma
-dialog.setmapbg.cyclemap=Cyclemap
-dialog.setmapbg.other=Inne
-dialog.setmapbg.server=Adres URL serwera
+dialog.setmapbg.intro=Wybierz dostawc\u0119 map t\u0142a lub dodaj nowego
+dialog.addmapsource.title=Dodaj dostawc\u0119 map
+dialog.addmapsource.sourcename=Nazwa dostawcy
+dialog.addmapsource.layer1url=URL pierwszej warstwy
+dialog.addmapsource.layer2url=Opcjonalny URL drugiej warstwy
+dialog.addmapsource.maxzoom=Maksymalny poziom zbli\u017cenia
+dialog.addmapsource.cloudstyle=Numer stylu
+dialog.addmapsource.noname=Nienazwane
 dialog.gpsies.column.name=Nazwa \u015bcie\u017cki
 dialog.gpsies.column.length=D\u0142ugo\u015b\u0107
 dialog.gpsies.description=Opis
@@ -304,6 +311,11 @@ dialog.about.systeminfo.povray=Povray zainstalowany
 dialog.about.systeminfo.exiftool=Exiftool zainstalowany
 dialog.about.systeminfo.gpsbabel=Gpsbabel zainstalowany
 dialog.about.systeminfo.gnuplot=Gnuplot zainstalowany
+dialog.about.systeminfo.exiflib=Biblioteka Exif
+dialog.about.systeminfo.exiflib.internal=Wewn\u0119trzny
+dialog.about.systeminfo.exiflib.internal.failed=Wewn\u0119trzny (nie znaleziony)
+dialog.about.systeminfo.exiflib.external=Zewn\u0119trzny
+dialog.about.systeminfo.exiflib.external.failed=Zewn\u0119trzny (nie znaleziony)
 dialog.about.yes=Tak
 dialog.about.no=Nie
 dialog.about.credits=Podzi\u0119kowania
@@ -339,11 +351,15 @@ dialog.saveconfig.prune.gpsbabelpath=\u015bcie\u017cka do gpsbabel
 dialog.saveconfig.prune.exiftoolpath=\u015bcie\u017cka do exiftool
 dialog.saveconfig.prune.mapserverindex=kolejny numer serwera map
 dialog.saveconfig.prune.mapserverurl=URL serwera map
+dialog.saveconfig.prune.mapsource=Wybrany dostawca map
+dialog.saveconfig.prune.mapsourcelist=Dostawcy map
+dialog.saveconfig.prune.diskcache=Pami\u0119\u0107 podr\u0119czna map
 dialog.saveconfig.prune.kmzimagewidth=szeroko\u015b\u0107 obrazka w KMZ
 dialog.saveconfig.prune.kmzimageheight=wysoko\u015b\u0107 obrazka w KMZ
 dialog.saveconfig.prune.colourscheme=Schemat kolor\u00f3w
 dialog.saveconfig.prune.kmltrackcolour=Kolor \u015bcie\u017cki w pliku KML
 dialog.setpaths.intro=Je\u015bli zachodzi tak potrzeba, mo\u017cesz wybra\u0107 \u015bcie\u017cki do aplikacji zewn\u0119trznych
+dialog.setpaths.found=Znalezione \u015bcie\u017cki?
 dialog.addaltitude.noaltitudes=Wybrany zakres nie zawiera danych o wysoko\u015bciach
 dialog.addaltitude.desc=Warto\u015b\u0107 przesuni\u0119cia wysoko\u015bci
 dialog.setcolours.intro=Kliknij na kolor by go wybra\u0107
@@ -364,6 +380,10 @@ dialog.setlanguage.secondintro=B\u0119dziesz musia\u0142 zapisa\u0107 ustawienia
 dialog.setlanguage.language=J\u0119zyk
 dialog.setlanguage.languagefile=Plik t\u0142umaczenia
 dialog.setlanguage.endmessage=Zapisz ustawienia i zrestartuj Prune\n by zmiana j\u0119zyka odnios\u0142a skutek.
+dialog.diskcache.save=Zapisz mapy na dysk
+dialog.diskcache.dir=katalog pami\u0119ci podr\u0119cznej
+dialog.diskcache.createdir=stw\u00f3rz katalog
+dialog.diskcache.nocreate=Nie utworzono katalogu pami\u0119ci podr\u0119cznej
 
 # 3d window
 dialog.3d.title=Prune widok tr\u00f3jwymiarowy
@@ -388,7 +408,7 @@ confirm.rearrangephotos=Zmieniono kolejno\u015b\u0107 zdj\u0119\u0107
 confirm.cutandmove=Przesuni\u0119to zaznaczenie
 confirm.convertnamestotimes=Zmieniono nazwy punkt\u00f3w po\u015brednich
 confirm.saveexif.ok1=Zapisano
-confirm.saveexif.ok2=pliki zdj\u0119\u0107
+confirm.saveexif.ok2=plik(\u00f3w) zdj\u0119\u0107
 confirm.undo.single=cofni\u0119to operacj\u0119
 confirm.undo.multi=operacje zosta\u0142y cofni\u0119te
 confirm.jpegload.single=dodano zdj\u0119cie
@@ -400,6 +420,8 @@ confirm.correlate.multi=zdj\u0119cia zosta\u0142y po\u0142\u0105czone
 confirm.createpoint=stworzono punkt
 confirm.rotatephoto=obr\u00f3cono zdj\u0119cie
 confirm.running=Przetwarzam dane ...
+confirm.lookupsrtm1=Znaleziono
+confirm.lookupsrtm2=warto\u015bci wysoko\u015bci
 
 # Buttons || These are all the texts for buttons
 button.ok=OK
@@ -429,6 +451,8 @@ button.showwebpage=Poka\u017c stron\u0119 web
 button.check=Sprawd\u017a
 button.resettodefaults=Przywr\u00f3\u0107 domy\u015blne
 button.browse=Przegl\u0105daj...
+button.addnew=Dodaj nowy
+button.delete=Usu\u0144
 
 # File types
 filetype.txt=Pliki TXT
@@ -443,6 +467,7 @@ filetype.svg=Pliki SVG
 # Display components || These are all for the side panels showing point/range details
 display.nodata=Nie za\u0142adowano danych
 display.noaltitudes=\u015acie\u017cki nie zawieraj\u0105 informacji o wysoko\u015bci
+display.notimestamps=\u015acie\u017cki nie zawieraj\u0105 informacji o czasie
 details.trackdetails=Szczeg\u00f3\u0142y \u015bcie\u017cki
 details.notrack=Brak za\u0142adowanych \u015bcie\u017cek
 details.track.points=Punkty
@@ -468,6 +493,7 @@ display.range.time.hours=h
 display.range.time.days=d
 details.range.avespeed=\u015arednia pr\u0119dko\u015b\u0107
 details.range.avemovingspeed=\u015arednie przesuni\u0119cie
+details.range.maxspeed=Pr\u0119dko\u015b\u0107 maksymalna
 details.range.numsegments=Liczba segment\u00f3w
 details.range.pace=Tempo
 details.range.gradient=Nachylenie
@@ -548,6 +574,7 @@ undo.rearrangephotos=zmie\u0144 kolejno\u015b\u0107 zdj\u0119\u0107
 undo.createpoint=stw\u00f3rz punkt
 undo.rotatephoto=obr\u00f3\u0107 zdj\u0119cie
 undo.convertnamestotimes=zamie\u0144 nazwy punkt\u00f3w
+undo.lookupsrtm=szukaj wysoko\u015bci w SRTM
 
 # Error messages
 error.save.dialogtitle=B\u0142\u0105d zapisu danych
@@ -571,6 +598,7 @@ error.jpegload.nofilesfound=Nie znaleziono plik\u00f3w
 error.jpegload.nojpegsfound=Nie znaleziono plik\u00f3w jpeg
 error.jpegload.noexiffound=Nie znaleziono informacji EXIF
 error.jpegload.nogpsfound=Nie znaleziono informacji GPS
+error.jpegload.exifreadfailed=Nie powiod\u0142o si\u0119 odczytanie informacji EXIF\nInformacji tych nie mo\u017cna przeczyta\u0107 bez wewn\u0119trznej lub zewn\u0119trznej biblioteki.
 error.gpsload.unknown=Nieznany b\u0142\u0105d
 error.undofailed.title=Cofnij nie powiod\u0142o si\u0119
 error.undofailed.text=Nie mo\u017cna cofn\u0105\u0107
@@ -584,3 +612,4 @@ error.osmimage.dialogtitle=B\u0142\u0105d przy \u0142adowaniu obraz\u00f3w map
 error.osmimage.failed=B\u0142\u0105d przy \u0142adowaniu obraz\u00f3w map. Sprawd\u017a po\u0142\u0105czenie z internetem.
 error.language.wrongfile=Wybrany plik nie jest plikiem z t\u0142umaczeniem dla Prune
 error.convertnamestotimes.nonames=\u017badne nazwy nie mog\u0142y zosta\u0107 zmienione na czas
+error.lookupsrtm.none=Nie znaleziono danych o wysoko\u015bci.
index cc444d064cd3475e6c14b00bd5cb8e0dbef4df56..6010a38ed1541c1a93d835f416a6054ef0239900 100644 (file)
@@ -3,34 +3,31 @@
 
 # Menu entries
 menu.file=Arquivo
-menu.file.open=Abrir
 menu.file.addphotos=Adicionar fotos
 menu.file.save=Salvar
 menu.file.exit=Sair
-menu.edit=Editar
 menu.track=Track
-menu.edit.undo=Desfazer
-menu.edit.clearundo=Limpar lista de desfazer
-menu.edit.editpoint=Editar ponto
-menu.edit.deletepoint=Remover ponto
-menu.edit.deleterange=Remover intervalo
-menu.edit.deletemarked=Remover pontos marcados
-menu.edit.interpolate=Interpolar
-menu.edit.average=Sele\u00e7\u00e3o m\u00e9dia
-menu.edit.reverse=Reverter intervalo
-menu.edit.mergetracksegments=Mesclar trechos da rota
-menu.edit.rearrange=Rearrumar pontos
-menu.edit.rearrange.start=Tudo para o in\u00edcio do arquivo
-menu.edit.rearrange.end=Tudo para o fim do arquivo
-menu.edit.rearrange.nearest=Cada um para o ponto da rota mais pr\u00f3ximo
-menu.edit.cutandmove=Recortar e mover sele\u00e7\u00e3o
-menu.select=Selecionar
+menu.track.undo=Desfazer
+menu.track.clearundo=Limpar lista de desfazer
+menu.point.editpoint=Editar ponto
+menu.point.deletepoint=Remover ponto
+menu.range.deleterange=Remover intervalo
+menu.track.deletemarked=Remover pontos marcados
+menu.range.interpolate=Interpolar
+menu.range.average=Sele\u00e7\u00e3o m\u00e9dia
+menu.range.reverse=Reverter intervalo
+menu.range.mergetracksegments=Mesclar trechos da rota
+menu.track.rearrange=Rearrumar pontos
+menu.track.rearrange.start=Tudo para o in\u00edcio do arquivo
+menu.track.rearrange.end=Tudo para o fim do arquivo
+menu.track.rearrange.nearest=Cada um para o ponto da rota mais pr\u00f3ximo
+menu.range.cutandmove=Recortar e mover sele\u00e7\u00e3o
 menu.range=Intervalo
 menu.point=Ponto
-menu.select.all=Selectionar tudo
-menu.select.none=N\u00e3o selecionar nenhuns
-menu.select.start=Definir in\u00edcio do intervalo
-menu.select.end=Definir fim do intervalo
+menu.range.all=Selectionar tudo
+menu.range.none=N\u00e3o selecionar nenhuns
+menu.range.start=Definir in\u00edcio do intervalo
+menu.range.end=Definir fim do intervalo
 menu.photo=Foto
 menu.photo.saveexif=Salvar para Exif
 menu.photo.connect=Conectar ao ponto
@@ -57,8 +54,6 @@ menu.map.showscalebar=Mostrar barra de escala
 
 # Alt keys for menus
 altkey.menu.file=A
-altkey.menu.edit=E
-altkey.menu.select=S
 altkey.menu.track=T
 altkey.menu.range=I
 altkey.menu.point=P
@@ -71,12 +66,13 @@ altkey.menu.help=J
 shortcut.menu.file.open=A
 shortcut.menu.file.load=C
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=C
-shortcut.menu.select.all=T
+shortcut.menu.range.all=T
 shortcut.menu.help.help=J
 
 # Functions
+function.open=Abrir
 function.loadfromgps=Carregar dados do GPS
 function.sendtogps=Enviar dados para o GPS
 function.exportkml=Exportar para KML
@@ -215,8 +211,6 @@ dialog.addtimeoffset.minutes=Minutos
 dialog.addtimeoffset.notimestamps=N\u00e3o foi poss\u00edvel adicionar uma diferen\u00e7a de tempo uma vez que esta sele\u00e7\u00e3o n\u00e3o possui nenhuma informa\u00e7\u00e3o de data-hora
 dialog.findwaypoint.intro=Insira parte do nome do ponto
 dialog.findwaypoint.search=Pesquisar
-dialog.connect.title=Conectar foto ao ponto
-dialog.connectphoto.clonepoint=Este ponto j\u00e1 possui uma foto.\n Voc\u00ea deseja fazer uma c\u00f3pia deste ponto?
 dialog.saveexif.title=Salvar Exif
 dialog.saveexif.intro=Selecionar as fotos para salvar usando as caixas de sele\u00e7\u00e3o
 dialog.saveexif.nothingtosave=Dados das coordenadas n\u00e3o foram alterados, nada para salvar
index e416762c00bdafdabb8484b572a71b5bb9212b33..ea0d138e1b7e14d314dc1a28a1ad2b35668f2c6c 100644 (file)
@@ -3,33 +3,30 @@
 
 # Menu entries
 menu.file=Fi\u015fier
-menu.file.open=Deschidere fi\u015fier
 menu.file.addphotos=Adaugare foto
 menu.file.save=Salvare
 menu.file.exit=Iesire
 menu.track=Traseu
-menu.edit=Editare
-menu.edit.undo=Anulare
-menu.edit.clearundo=\u015etergere lista de anulari
-menu.edit.editpoint=Editare punct
-menu.edit.deletepoint=\u015etergere punct
-menu.edit.deleterange=\u015etergere gama
-menu.edit.deletemarked=\u015etergere puncte marcate
-menu.edit.interpolate=Interpolare
-menu.edit.average=Mediere selectie
-menu.edit.reverse=Inversare selectie
-menu.edit.mergetracksegments=Unire segmente traseu
-menu.edit.rearrange=Rearanjare waypoint
-menu.edit.rearrange.start=Toate la inceputul fisierului
-menu.edit.rearrange.end=Toate la sfarsitul fisierului
-menu.edit.rearrange.nearest=Fiecare la punctul cel mai apropiat al traseului
-menu.edit.cutandmove=Taiere si mutare selectie
+menu.track.undo=Anulare
+menu.track.clearundo=\u015etergere lista de anulari
+menu.point.editpoint=Editare punct
+menu.point.deletepoint=\u015etergere punct
+menu.range.deleterange=\u015etergere gama
+menu.track.deletemarked=\u015etergere puncte marcate
+menu.range.interpolate=Interpolare
+menu.range.average=Mediere selectie
+menu.range.reverse=Inversare selectie
+menu.range.mergetracksegments=Unire segmente traseu
+menu.track.rearrange=Rearanjare waypoint
+menu.track.rearrange.start=Toate la inceputul fisierului
+menu.track.rearrange.end=Toate la sfarsitul fisierului
+menu.track.rearrange.nearest=Fiecare la punctul cel mai apropiat al traseului
+menu.range.cutandmove=Taiere si mutare selectie
 menu.point=Punct
-menu.select=Selectare
-menu.select.all=Selectare toate
-menu.select.none=Nu selecta niciun punct
-menu.select.start=Seteaza inceputul selectiei
-menu.select.end=Seteaza sfarsitul selectiei
+menu.range.all=Selectare toate
+menu.range.none=Nu selecta niciun punct
+menu.range.start=Seteaza inceputul selectiei
+menu.range.end=Seteaza sfarsitul selectiei
 menu.photo=Foto
 menu.photo.saveexif=Salveaza la Exif
 menu.photo.connect=Conecteaza la punct
@@ -63,10 +60,11 @@ altkey.menu.help=A
 # Ctrl shortcuts for menu items
 shortcut.menu.file.open=D
 shortcut.menu.file.save=S
-shortcut.menu.edit.undo=Z
-shortcut.menu.select.all=T
+shortcut.menu.track.undo=Z
+shortcut.menu.range.all=T
 
 # Functions
+function.open=Deschidere fi\u015fier
 function.loadfromgps=\u00cencarc\u0103 date de la GPS
 function.sendtogps=Trimite date spre GPS
 function.exportkml=Export\u0103 \u00eentr-un fi\u015fier KML
@@ -129,8 +127,6 @@ dialog.saveexif.overwrite=Suprascrie fisiere
 dialog.charts.xaxis=Axa X
 dialog.charts.yaxis=Axa Y
 dialog.distances.currentpoint=Punct curent
-dialog.setmapbg.mapnik=Mapnik (implicit)
-dialog.setmapbg.server=Adres\u0103 server
 dialog.gpsies.column.length=Lungime
 dialog.gpsies.description=Descriere
 dialog.gpsies.nodescription=Fara descriere
index 20fe68933d43a403ccd5f0ea591c7cad30844b9d..59fa48f217cb05cd9d2dba4b73ba45dac704c28e 100644 (file)
@@ -3,34 +3,31 @@
 
 # Menu entries
 menu.file=Dosya
-menu.file.open=Dosya a\u00e7
 menu.file.addphotos=Foto ekle
 menu.file.save=Kaydet
 menu.file.exit=Ç\u0131k\u0131\u015f
-menu.edit=D\u00fczenle
 menu.track=\u0130z
-menu.edit.undo=Geri al
-menu.edit.clearundo=Geri alma listesi s\u0131f\u0131rla
-menu.edit.editpoint=Nokta d\u00fczenle
-menu.edit.deletepoint=Noktay\u0131 sil
-menu.edit.deleterange=S\u0131ray\u0131 sil
-menu.edit.deletemarked=Se\u00e7ili noktalar\u0131 sil
-menu.edit.interpolate=\u0130nterpolasyon
-menu.edit.average=Se\u00e7me ortala
-menu.edit.reverse=S\u0131ra tersine \u00e7evir
-menu.edit.mergetracksegments=\u0130z par\u00e7alar\u0131 birle\u015ftir
-menu.edit.rearrange=Yol noktalar\u0131 yeniden diz
-menu.edit.rearrange.start=Hepsini dosyan\u0131n ba\u015f\u0131na
-menu.edit.rearrange.end=Hepsini dosyan\u0131n sonuna
-menu.edit.rearrange.nearest=En yak\u0131n iz noktaya
-menu.edit.cutandmove=Se\u00e7me kes ve ta\u015f\u0131
-menu.select=Se\u00e7
+menu.track.undo=Geri al
+menu.track.clearundo=Geri alma listesi s\u0131f\u0131rla
+menu.point.editpoint=Nokta d\u00fczenle
+menu.point.deletepoint=Noktay\u0131 sil
+menu.range.deleterange=S\u0131ray\u0131 sil
+menu.track.deletemarked=Se\u00e7ili noktalar\u0131 sil
+menu.range.interpolate=\u0130nterpolasyon
+menu.range.average=Se\u00e7me ortala
+menu.range.reverse=S\u0131ra tersine \u00e7evir
+menu.range.mergetracksegments=\u0130z par\u00e7alar\u0131 birle\u015ftir
+menu.track.rearrange=Yol noktalar\u0131 yeniden diz
+menu.track.rearrange.start=Hepsini dosyan\u0131n ba\u015f\u0131na
+menu.track.rearrange.end=Hepsini dosyan\u0131n sonuna
+menu.track.rearrange.nearest=En yak\u0131n iz noktaya
+menu.range.cutandmove=Se\u00e7me kes ve ta\u015f\u0131
 menu.range=S\u0131ra
 menu.point=Nokta
-menu.select.all=Hepsini se\u00e7
-menu.select.none=Hi\u00e7 se\u00e7
-menu.select.start=S\u0131ran\u0131n ba\u015fkang\u0131c\u0131 se\u00e7
-menu.select.end=S\u0131ran\u0131n sonu se\u00e7
+menu.range.all=Hepsini se\u00e7
+menu.range.none=Hi\u00e7 se\u00e7
+menu.range.start=S\u0131ran\u0131n ba\u015fkang\u0131c\u0131 se\u00e7
+menu.range.end=S\u0131ran\u0131n sonu se\u00e7
 menu.photo=Foto
 menu.photo.saveexif=Exif'te kaydet
 menu.photo.connect=Noktaya ba\u011flan
@@ -44,7 +41,6 @@ menu.view.browser.mapquest=Mapquest
 menu.view.browser.yahoo=Yahoo haritalar\u0131
 menu.view.browser.bing=Bing haritalar\u0131
 menu.settings=Ayarlar
-menu.settings.showpace=H\u0131z\u0131 g\u00f6r\u00fcnt\u00fcle
 menu.help=Yard\u0131m
 # Popup menu for map
 menu.map.zoomin=Yak\u0131nla\u015ft\u0131r
@@ -56,8 +52,6 @@ menu.map.showscalebar=\u00d6l\u00e7e\u011fi g\u00f6r\u00fcnt\u00fcle
 
 # Alt keys for menus
 altkey.menu.file=D
-altkey.menu.edit=Z
-altkey.menu.select=S
 altkey.menu.track=Z
 altkey.menu.range=S
 altkey.menu.point=N
@@ -70,12 +64,13 @@ altkey.menu.help=Y
 shortcut.menu.file.open=A
 shortcut.menu.file.load=L
 shortcut.menu.file.save=K
-shortcut.menu.edit.undo=Z
+shortcut.menu.track.undo=Z
 shortcut.menu.edit.compress=C
-shortcut.menu.select.all=A
+shortcut.menu.range.all=A
 shortcut.menu.help.help=Y
 
 # Functions
+function.open=Dosya a\u00e7
 function.loadfromgps=GPS'den veri al
 function.sendtogps=GPS'e veri g\u00f6nder
 function.exportkml=Ver KML olarak
@@ -270,7 +265,6 @@ dialog.saveconfig.prune.gpsbabelpath=gpsbabel'in yeriyolu
 dialog.saveconfig.prune.exiftoolpath=exiftool'un yeriyolu
 dialog.saveconfig.prune.mapserverindex=Harita sunucunun index
 dialog.saveconfig.prune.mapserverurl=Harita sunucunun adresi
-dialog.saveconfig.prune.showpace=H\u0131z\u0131 g\u00f6r\u00fcnt\u00fcle
 dialog.saveconfig.prune.kmzimagewidth=KMZ resim geni\u015fli\u011fi
 dialog.saveconfig.prune.kmzimageheight=KMZ resim y\u00fcksekli\u011fi
 dialog.setpaths.intro=\u0130ste\u011fe ba\u011fl\u0131 a\u015fa\u011f\u0131daki uygulamalar\u0131n veriyolu kaydedebilirsin:
index ba1c391460f3b6b22c62d7e75f890d387ae3b112..5bf076411332602d99a8d0710afe569259dc11ba 100644 (file)
@@ -3,31 +3,28 @@
 
 # Menu entries
 menu.file=\u6587\u4ef6
-menu.file.open=\u6253\u5f00
 menu.file.addphotos=\u6dfb\u52a0\u76f8\u7247
 menu.file.save=\u4fdd\u5b58
 menu.file.exit=\u9000\u51fa
-menu.edit=\u7f16\u8f91
-menu.edit.undo=\u64a4\u9500
-menu.edit.clearundo=\u6e05\u9664\u64a4\u9500\u6e05\u5355
-menu.edit.editpoint=\u7f16\u8f91\u8f68\u8ff9\u70b9
-menu.edit.deletepoint=\u5220\u9664\u8f68\u8ff9\u70b9
-menu.edit.deleterange=\u5220\u9664\u8f68\u8ff9\u70b9\u6bb5
-menu.edit.deletemarked=\u5220\u9664\u5df2\u6807\u793a\u8f68\u8ff9\u70b9
-menu.edit.interpolate=\u63d2\u5165\u8f68\u8ff9\u70b9
-menu.edit.average=\u8bbe\u7f6e\u5e73\u5747\u8f68\u8ff9\u70b9
-menu.edit.reverse=\u8f68\u8ff9\u70b9\u53cd\u5411
-menu.edit.mergetracksegments=\u5408\u5e76\u8f68\u8ff9\u6bb5
-menu.edit.rearrange=\u822a\u70b9\u91cd\u7f6e
-menu.edit.rearrange.start=\u81f3\u8d77\u59cb\u4f4d\u7f6e
-menu.edit.rearrange.end=\u81f3\u672b\u4f4d\u7f6e
-menu.edit.rearrange.nearest=\u81f3\u6700\u8fd1\u8f68\u8ff9\u70b9
-menu.edit.cutandmove=\u79fb\u52a8
-menu.select=\u9009\u62e9
-menu.select.all=\u5168\u9009
-menu.select.none=\u64a4\u9500\u9009\u62e9
-menu.select.start=\u8bbe\u7f6e\u8d77\u70b9
-menu.select.end=\u8bbe\u7f6e\u672b\u70b9
+menu.track.undo=\u64a4\u9500
+menu.track.clearundo=\u6e05\u9664\u64a4\u9500\u6e05\u5355
+menu.point.editpoint=\u7f16\u8f91\u8f68\u8ff9\u70b9
+menu.point.deletepoint=\u5220\u9664\u8f68\u8ff9\u70b9
+menu.range.deleterange=\u5220\u9664\u8f68\u8ff9\u70b9\u6bb5
+menu.track.deletemarked=\u5220\u9664\u5df2\u6807\u793a\u8f68\u8ff9\u70b9
+menu.range.interpolate=\u63d2\u5165\u8f68\u8ff9\u70b9
+menu.range.average=\u8bbe\u7f6e\u5e73\u5747\u8f68\u8ff9\u70b9
+menu.range.reverse=\u8f68\u8ff9\u70b9\u53cd\u5411
+menu.range.mergetracksegments=\u5408\u5e76\u8f68\u8ff9\u6bb5
+menu.track.rearrange=\u822a\u70b9\u91cd\u7f6e
+menu.track.rearrange.start=\u81f3\u8d77\u59cb\u4f4d\u7f6e
+menu.track.rearrange.end=\u81f3\u672b\u4f4d\u7f6e
+menu.track.rearrange.nearest=\u81f3\u6700\u8fd1\u8f68\u8ff9\u70b9
+menu.range.cutandmove=\u79fb\u52a8
+menu.range.all=\u5168\u9009
+menu.range.none=\u64a4\u9500\u9009\u62e9
+menu.range.start=\u8bbe\u7f6e\u8d77\u70b9
+menu.range.end=\u8bbe\u7f6e\u672b\u70b9
 menu.photo=\u76f8\u7247
 menu.photo.saveexif=\u5750\u6807\u4fdd\u5b58\u81f3Exif
 menu.photo.connect=\u94fe\u63a5\u76f8\u7247
@@ -40,7 +37,6 @@ menu.view.browser.openstreetmap=Openstreet\u5730\u56fe
 menu.view.browser.mapquest=Mapquest\u5730\u56fe
 menu.view.browser.yahoo=Yahoo\u5730\u56fe
 menu.settings=\u8bbe\u7f6e
-menu.settings.showpace=\u663e\u793a\u6b65\u901f
 menu.help=\u5e2e\u52a9
 # Popup menu for map
 menu.map.zoomin=\u653e\u5927
@@ -53,6 +49,7 @@ menu.map.showmap=\u663e\u793a\u5730\u56fe
 menu.map.showscalebar=\u663e\u793a\u6bd4\u4f8b\u5c3a
 
 # Functions
+function.open=\u6253\u5f00
 function.loadfromgps=\u4eceGPS\u5bfc\u5165
 function.sendtogps=\u53d1\u9001\u81f3GPS
 function.exportkml=\u8f93\u51faKML\u6587\u4ef6
@@ -176,8 +173,6 @@ dialog.addtimeoffset.minutes=\u5206\u949f
 dialog.addtimeoffset.notimestamps=\u4e0d\u80fd\u6dfb\u52a0\u65f6\u95f4\u56e0\u4e3a\u6b64\u6bb5\u4e0d\u542b\u65f6\u95f4\u4fe1\u606f
 dialog.findwaypoint.intro=\u8f93\u5165\u90e8\u5206\u822a\u70b9\u540d
 dialog.findwaypoint.search=\u641c\u7d22
-dialog.connect.title=\u94fe\u63a5\u7167\u7247\u548c\u822a\u70b9
-dialog.connectphoto.clonepoint=\u6b64\u8f68\u8ff9\u70b9\u5df2\u6709\u50cf\u7247\n\u662f\u5426\u590d\u5236\u822a\u70b9\uff1f
 dialog.saveexif.title=\u4fdd\u5b58Exif
 dialog.saveexif.intro=\u9009\u62e9\u8981\u4fdd\u5b58\u7684\u76f8\u7247
 dialog.saveexif.nothingtosave=\u5750\u6807\u672a\u6539\u53d8\uff0c\u65e0\u4fdd\u5b58\u5185\u5bb9
@@ -292,7 +287,6 @@ dialog.saveconfig.prune.gpsbabelpath=gpsbabel\u8def\u5f84
 dialog.saveconfig.prune.exiftoolpath=exiftool\u8def\u5f84
 dialog.saveconfig.prune.mapserverindex=\u80cc\u666f\u5730\u56fe\u7801(1-4)
 dialog.saveconfig.prune.mapserverurl=\u90094\u65f6\u5730\u56fe\u670d\u52a1\u5668URL
-dialog.saveconfig.prune.showpace=\u663e\u793a\u6b65\u901f
 dialog.saveconfig.prune.kmzimagewidth=KMZ\u56fe\u50cf\u5bbd\u5ea6
 dialog.saveconfig.prune.kmzimageheight=KMZ\u56fe\u50cf\u9ad8\u5ea6
 dialog.setpaths.intro=\u82e5\u9700\u8981\uff0c\u53ef\u8bbe\u5b9a\u5916\u6302\u7a0b\u5e8f\u8def\u5f84
index 08b29fad02e6b32ec2cfc6bafa663869d76cbefa..fabcb4dde5d6e7bfe14d849f18189ba2f8f1d006 100644 (file)
@@ -21,15 +21,14 @@ import tim.prune.I18nManager;
 import tim.prune.config.Config;
 import tim.prune.data.Altitude;
 import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
 import tim.prune.data.LatLonRectangle;
 import tim.prune.data.Latitude;
 import tim.prune.data.Longitude;
 import tim.prune.data.Photo;
 import tim.prune.data.Timestamp;
-import tim.prune.drew.jpeg.ExifReader;
-import tim.prune.drew.jpeg.JpegData;
-import tim.prune.drew.jpeg.JpegException;
-import tim.prune.drew.jpeg.Rational;
+import tim.prune.jpeg.ExifGateway;
+import tim.prune.jpeg.JpegData;
 
 /**
  * Class to manage the loading of Jpegs and dealing with the GPS data from them
@@ -250,19 +249,19 @@ public class JpegLoader implements Runnable
 
                // Create Photo object
                Photo photo = new Photo(inFile);
+               if (inFile.exists() && inFile.canRead()) {
+                       _fileCounts[1]++; // jpeg found
+               }
                // Try to get information out of exif
-               try
+               JpegData jpegData = ExifGateway.getJpegData(inFile);
+               Timestamp timestamp = null;
+               if (jpegData != null)
                {
-                       JpegData jpegData = new ExifReader(inFile).extract();
-                       _fileCounts[1]++; // jpeg found (no exception thrown)
                        if (jpegData.getExifDataPresent())
                                {_fileCounts[2]++;} // exif found
-                       if (jpegData.isValid())
+                       if (jpegData.isGpsValid())
                        {
-                               if (jpegData.getGpsDatestamp() != null && jpegData.getGpsTimestamp() != null)
-                               {
-                                       photo.setTimestamp(createTimestamp(jpegData.getGpsDatestamp(), jpegData.getGpsTimestamp()));
-                               }
+                               timestamp = createTimestamp(jpegData.getGpsDatestamp(), jpegData.getGpsTimestamp());
                                // Make DataPoint and attach to Photo
                                DataPoint point = createDataPoint(jpegData);
                                point.setPhoto(photo);
@@ -272,19 +271,21 @@ public class JpegLoader implements Runnable
                                _fileCounts[3]++;
                        }
                        // Use exif timestamp if gps timestamp not available
-                       if (photo.getTimestamp() == null && jpegData.getOriginalTimestamp() != null)
-                       {
-                               photo.setTimestamp(createTimestamp(jpegData.getOriginalTimestamp()));
+                       if (timestamp == null && jpegData.getOriginalTimestamp() != null) {
+                               timestamp = createTimestamp(jpegData.getOriginalTimestamp());
                        }
                        photo.setExifThumbnail(jpegData.getThumbnailImage());
                        // Also extract orientation tag for setting rotation state of photo
                        photo.setRotation(jpegData.getRequiredRotation());
                }
-               catch (JpegException jpe) { // don't list errors, just count them
-               }
                // Use file timestamp if exif timestamp isn't available
-               if (photo.getTimestamp() == null) {
-                       photo.setTimestamp(new Timestamp(inFile.lastModified()));
+               if (timestamp == null) {
+                       timestamp = new Timestamp(inFile.lastModified());
+               }
+               // Apply timestamp to photo and its point (if any)
+               photo.setTimestamp(timestamp);
+               if (photo.getDataPoint() != null) {
+                       photo.getDataPoint().setFieldValue(Field.TIMESTAMP, timestamp.getText(Timestamp.FORMAT_ISO_8601), false);
                }
                // Check the criteria for adding the photo - check whether the photo has coordinates and if so if they're within the rectangle
                if ( (photo.getDataPoint() != null || _noExifCheckbox.isSelected())
@@ -350,26 +351,25 @@ public class JpegLoader implements Runnable
                        inData.getLongitudeRef() == 'E' || inData.getLongitudeRef() == 'e');
                Longitude longitude = new Longitude(lonval, Longitude.FORMAT_DEG_MIN_SEC);
                Altitude altitude = null;
-               if (inData.getAltitude() != null)
-               {
-                       altitude = new Altitude(inData.getAltitude().intValue(), Altitude.Format.METRES);
+               if (inData.hasAltitude()) {
+                       altitude = new Altitude(inData.getAltitude(), Altitude.Format.METRES);
                }
                return new DataPoint(latitude, longitude, altitude);
        }
 
 
        /**
-        * Convert an array of 3 Rational numbers into a double coordinate value
-        * @param inRationals array of three Rational objects
+        * Convert an array of 3 doubles (deg-min-sec) into a double coordinate value
+        * @param inValues array of three doubles for deg-min-sec
         * @param isPositive true for positive hemisphere, for positive double value
         * @return double value of coordinate, either positive or negative
         */
-       private static double getCoordinateDoubleValue(Rational[] inRationals, boolean isPositive)
+       private static double getCoordinateDoubleValue(double[] inValues, boolean isPositive)
        {
-               if (inRationals == null || inRationals.length != 3) return 0.0;
-               double value = inRationals[0].doubleValue()        // degrees
-                       + inRationals[1].doubleValue() / 60.0          // minutes
-                       + inRationals[2].doubleValue() / 60.0 / 60.0;  // seconds
+               if (inValues == null || inValues.length != 3) return 0.0;
+               double value = inValues[0]        // degrees
+                       + inValues[1] / 60.0          // minutes
+                       + inValues[2] / 60.0 / 60.0;  // seconds
                // make sure it's the correct sign
                value = Math.abs(value);
                if (!isPositive) value = -value;
@@ -378,15 +378,18 @@ public class JpegLoader implements Runnable
 
 
        /**
-        * Use the given Rational values to create a timestamp
-        * @param inDate rationals describing date
-        * @param inTime rationals describing time
+        * Use the given int values to create a timestamp
+        * @param inDate ints describing date
+        * @param inTime ints describing time
         * @return Timestamp object corresponding to inputs
         */
-       private static Timestamp createTimestamp(Rational[] inDate, Rational[] inTime)
+       private static Timestamp createTimestamp(int[] inDate, int[] inTime)
        {
-               return new Timestamp(inDate[0].intValue(), inDate[1].intValue(), inDate[2].intValue(),
-                       inTime[0].intValue(), inTime[1].intValue(), inTime[2].intValue());
+               if (inDate == null || inTime == null || inDate.length != 3 || inTime.length != 3) {
+                       return null;
+               }
+               return new Timestamp(inDate[0], inDate[1], inDate[2],
+                       inTime[0], inTime[1], inTime[2]);
        }
 
 
index 090bb6d3a9a0c738b3ad1e71c64e512a9e0a4922..76ed15785dc1fff93ec18661790e8c9955539711 100644 (file)
@@ -36,6 +36,7 @@ public class NmeaFileLoader
        {
                BufferedReader reader = null;
                ArrayList<NmeaMessage> messages = new ArrayList<NmeaMessage>();
+               String lastDate = null;
                try
                {
                        reader = new BufferedReader(new FileReader(inFile));
@@ -46,17 +47,32 @@ public class NmeaFileLoader
                                // Try to make an NmeaMessage object for each line of file
                                if (currLine.trim().length() > 0)
                                {
-                                       NmeaMessage message = processLine(currLine);
+                                       NmeaMessage message = processGGA(currLine);
                                        if (message != null)
                                        {
-                                               if (message.hasFix()) {
+                                               if (message.hasFix())
+                                               {
                                                        message.setSegment(newSegment);
+                                                       message.setDate(lastDate);
                                                        // add message to list
                                                        messages.add(message);
                                                }
                                                // Start a new segment if fix lost
                                                newSegment = !message.hasFix();
                                        }
+                                       else {
+                                               String date = getDateFromRMC(currLine);
+                                               if (date != null)
+                                               {
+                                                       if (lastDate == null && !messages.isEmpty()) {
+                                                               // Backfill first few messages received before the first date
+                                                               for (int m=0; m<messages.size(); m++) {
+                                                                       messages.get(m).setDate(date);
+                                                               }
+                                                       }
+                                                       lastDate = date;
+                                               }
+                                       }
                                }
                                // Read next line, if any
                                currLine = reader.readLine();
@@ -68,8 +84,7 @@ public class NmeaFileLoader
                finally
                {
                        // close file ignoring errors
-                       try
-                       {
+                       try {
                                if (reader != null) reader.close();
                        }
                        catch (Exception e) {}
@@ -82,17 +97,16 @@ public class NmeaFileLoader
        }
 
        /**
-        * Process the given NMEA line and return the message
+        * Process the given GGA sentence and return the message
         * @param inLine line to process
         * @return message object
         */
-       private static NmeaMessage processLine(String inLine)
+       private static NmeaMessage processGGA(String inLine)
        {
                // Only consider lines which are long enough and begin with the GPS position sentence
                if (inLine == null || inLine.length() < 20 || !inLine.startsWith("$GPGGA")) {
                        return null;
                }
-               // TODO: May be possible to pull date out of GPRMC messages, but then need to back-populate
                // Assume comma delimiter, split into array
                String[] splitLine = inLine.split(",");
                if (splitLine != null && splitLine.length >= 10)
@@ -107,6 +121,27 @@ public class NmeaFileLoader
                return null;
        }
 
+       /**
+        * Process the given MRC sentence and return the date
+        * @param inLine line to process
+        * @return date, if any
+        */
+       private static String getDateFromRMC(String inLine)
+       {
+               // Only consider lines which are long enough and begin with the RMC sentence
+               if (inLine == null || inLine.length() < 20 || !inLine.startsWith("$GPRMC")) {
+                       return null;
+               }
+               // Assume comma delimiter, split into array
+               String[] splitLine = inLine.split(",");
+               if (splitLine != null && splitLine.length >= 10)
+               {
+                       return splitLine[9]; // date in position 9
+               }
+               // Couldn't parse it, return null
+               return null;
+       }
+
        /**
         * Make an object array from the data list
         * @param inList list of messages
index e524e3922c7e5b69b2ba7d4580e035c3dbdbaeac..83f5382b5e0b32b67e2c7f6e82fe1d64dad34059 100644 (file)
@@ -11,6 +11,7 @@ public class NmeaMessage
        private String _longitude = null;
        private String _altitude = null;
        private String _timestamp = null;
+       private String _date = null;
        private boolean _fix = false;
        private boolean _segment = false;
 
@@ -47,6 +48,13 @@ public class NmeaMessage
                _segment = inSegment;
        }
 
+       /**
+        * @param inDate date from MRC sentence
+        */
+       public void setDate(String inDate) {
+               _date = inDate;
+       }
+
        /**
         * @return String array for loading
         */
@@ -83,6 +91,17 @@ public class NmeaMessage
                try
                {
                        Calendar cal = Calendar.getInstance();
+                       // use date if available (today if not)
+                       if (_date != null && _date.length() == 6) {
+                               try {
+                                       cal.set(Calendar.DAY_OF_MONTH, Integer.parseInt(_date.substring(0, 2)));
+                                       cal.set(Calendar.MONTH, Integer.parseInt(_date.substring(2, 4))-1); // month starts at zero
+                                       int year = Integer.parseInt(_date.substring(4, 6));
+                                       if (year < 80) {year += 2000;} else {year += 1900;} // two-digit year hack
+                                       cal.set(Calendar.YEAR, year);
+                               }
+                               catch (Exception e) {} // ignore exceptions for date, still take time
+                       }
                        cal.set(Calendar.HOUR_OF_DAY, Integer.parseInt(_timestamp.substring(0, 2)));
                        cal.set(Calendar.MINUTE, Integer.parseInt(_timestamp.substring(2, 4)));
                        cal.set(Calendar.SECOND, Integer.parseInt(_timestamp.substring(4, 6)));
index dfeec526cb0ddfe190d76621cf7ac1747ea41130..2d0f1693226cced1a8dd8aafd057d32fd506e936 100644 (file)
@@ -80,7 +80,7 @@ public class ZipFileLoader
                        }
                }
                catch (Exception e) {
-                       System.err.println("Error: " + e.getClass().getName() + " -message= " + e.getMessage());
+                       System.err.println("ZipFile Error: " + e.getClass().getName() + " -message= " + e.getMessage());
                }
        }
 
@@ -125,7 +125,7 @@ public class ZipFileLoader
                        }
                }
                catch (Exception e) {
-                       System.err.println("Error: " + e.getClass().getName() + " -message= " + e.getMessage());
+                       System.err.println("ZipStream Error: " + e.getClass().getName() + " -message= " + e.getMessage());
                }
        }
 }
index 8108b006b3fd7c749bb03627e634ddf7df390677..355ac71ec52e595156f13665a02f06480c22149d 100644 (file)
@@ -1,5 +1,5 @@
-Prune version 9
-===============
+Prune version 10
+================
 
 Prune is an application for viewing, editing and managing coordinate data from GPS systems,
 including format conversion, charting and photo correlation.
@@ -17,7 +17,7 @@ Running
 =======
 
 To run Prune from the jar file, simply call it from a command prompt or shell:
-   java -jar prune_09.jar
+   java -jar prune_10.jar
 
 If the jar file is saved in a different directory, you will need to include the path.
 Depending on your system settings, you may be able to click or double-click on the jar file
@@ -25,7 +25,19 @@ in a file manager window to execute it.  A shortcut, menu item, alias, desktop i
 or other link can of course be made should you wish.
 
 To specify a language other than the default, use an additional parameter, eg:
-   java -jar prune_09.jar --lang=DE
+   java -jar prune_10.jar --lang=DE
+
+New with version 10
+===================
+
+The following features were added since version 9:
+  - Function to lookup altitudes using SRTM data from the Space Shuttle
+  - Choice between altitude profile and speed profile in main view
+  - Caching of map tiles to disk for faster access
+  - Offline mode where maps are only retrieved from disk
+  - Storage of multiple custom map sources, not just one custom one
+  - Use of maps with multiple layers (like maps-for-free)
+  - Use of cloudmade maps
 
 New with version 9
 ==================
index ef1f3d56839483af8a80c078e8a4f29d91ed7aca..b7a339904288badc340f2897e7e7caebb08e71fc 100644 (file)
@@ -56,7 +56,7 @@ public class GpxCacher extends DefaultHandler
                                        saxParser.parse(new GZIPInputStream(new FileInputStream(inInfo.getFile())), this);
                                }
                                else {
-                                       System.out.println("Unrecognised file type: " + inInfo.getFile().getName());
+                                       System.out.println("GpxCacher unrecognised file type: " + inInfo.getFile().getName());
                                }
                        } catch (Exception e) {
                                // TODO: Handle errors here with a list of warnings?
diff --git a/tim/prune/undo/UndoLookupSrtm.java b/tim/prune/undo/UndoLookupSrtm.java
new file mode 100644 (file)
index 0000000..2672bd5
--- /dev/null
@@ -0,0 +1,64 @@
+package tim.prune.undo;
+
+import tim.prune.I18nManager;
+import tim.prune.UpdateMessageBroker;
+import tim.prune.data.DataPoint;
+import tim.prune.data.Field;
+import tim.prune.data.Track;
+import tim.prune.data.TrackInfo;
+
+/**
+ * Undo lookup of altitudes from SRTM data
+ */
+public class UndoLookupSrtm implements UndoOperation
+{
+       /** DataPoint objects which didn't have altitudes before */
+       private DataPoint[] _points;
+
+
+       /**
+        * Constructor
+        * @param inTrackInfo track info object
+        */
+       public UndoLookupSrtm(TrackInfo inTrackInfo)
+       {
+               Track track = inTrackInfo.getTrack();
+               int numPoints = track.getNumPoints();
+               // Make array of points without altitudes
+               _points = new DataPoint[numPoints];
+               for (int i=0; i<numPoints; i++) {
+                       DataPoint point = track.getPoint(i);
+                       if (!point.hasAltitude()) {
+                               _points[i] = point;
+                       }
+               }
+       }
+
+
+       /**
+        * @return description of operation
+        */
+       public String getDescription()
+       {
+               return I18nManager.getText("undo.lookupsrtm");
+       }
+
+
+       /**
+        * Perform the undo operation on the given Track
+        * @param inTrackInfo TrackInfo object on which to perform the operation
+        */
+       public void performUndo(TrackInfo inTrackInfo) throws UndoException
+       {
+               // Loop through points again, and reset altitudes if they have one
+               final int numPoints = _points.length;
+               for (int i=0; i<numPoints; i++) {
+                       DataPoint point = _points[i];
+                       if (point != null && point.hasAltitude()) {
+                               point.setFieldValue(Field.ALTITUDE, null, true);
+                       }
+               }
+               _points = null;
+               UpdateMessageBroker.informSubscribers();
+       }
+}