+set -e
# Build script
+ set -e
# Version number
- PRUNENAME=gpsprune_19.2
+ PRUNENAME=gpsprune_20
# remove compile directory
rm -rf compile
# remove dist directory
cp -r src/tim/prune/*.txt compile/tim/prune/
cp -r src/tim/prune/gui/images compile/tim/prune/gui/
cp src/tim/prune/function/srtm/srtmtiles.dat compile/tim/prune/function/srtm
+mkdir compile/tim/prune/function/srtm/viewfinder/
+cp src/tim/prune/function/srtm/viewfinder/tiles.dat compile/tim/prune/function/srtm/viewfinder/
# make dist directory
mkdir dist
# build into jar file
<groupId>tim.prune</groupId>
<artifactId>gpsprune</artifactId>
- <version>19.2</version>
+ <version>20</version>
<packaging>jar</packaging>
<name>tim.prune.gpsprune</name>
<include>tim/prune/gui/images/*</include>
<include>tim/prune/lang/*</include>
<include>tim/prune/function/srtm/srtmtiles.dat</include>
+ <include>tim/prune/function/srtm/viewfinder/tiles.dat</include>
<include>tim/prune/*.txt</include>
</includes>
</resource>
<plugin>
<artifactId>maven-compiler-plugin</artifactId>
<version>3.8.0</version>
+ <configuration>
+ <compilerArgs>
+ <arg>-Xlint:deprecation</arg>
+ </compilerArgs>
+ </configuration>
</plugin>
<plugin>
<artifactId>maven-jar-plugin</artifactId>
{
// Instance variables
private JFrame _frame = null;
+ private String _titlePrefix = null;
private Track _track = null;
private TrackInfo _trackInfo = null;
private int _lastSavePosition = 0;
private AppMode _appMode = AppMode.NORMAL;
/** Enum for the app mode - currently only two options but may expand later */
- public enum AppMode {NORMAL, DRAWRECT};
+ public enum AppMode {NORMAL, DRAWRECT}
/**
public App(JFrame inFrame)
{
_frame = inFrame;
+ _titlePrefix = _frame.getTitle();
_undoStack = new UndoStack();
_track = new Track();
_trackInfo = new TrackInfo(_track);
}
+ /**
+ * Remove altitudes from selected points
+ */
+ public void removeAltitudes(int selStart, int selEnd)
+ {
+ UndoRemoveAltitudes undo = new UndoRemoveAltitudes(_trackInfo, selStart, selEnd);
+ if (_trackInfo.getTrack().removeAltitudes(selStart, selEnd))
+ {
+ _undoStack.add(undo);
+ _trackInfo.getSelection().markInvalid();
+ UpdateMessageBroker.informSubscribers(DataSubscriber.DATA_EDITED);
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.removealtitudes"));
+ }
+ }
+
+
/**
* Merge the track segments within the current selection
*/
loadedTrack.load(inFieldArray, inDataArray, inOptions);
if (loadedTrack.getNumPoints() <= 0)
{
- showErrorMessage("error.load.dialogtitle", "error.load.nopoints");
+ String msgKey = (inSourceInfo == null ? "error.load.nopointsintext" : "error.load.nopoints");
+ showErrorMessage("error.load.dialogtitle", msgKey);
// load next file if there's a queue
loadNextFile();
return;
undo.setNumPhotosAudios(_trackInfo.getPhotoList().getNumPhotos(), _trackInfo.getAudioList().getNumAudios());
_undoStack.add(undo);
_track.combine(inLoadedTrack);
- // set source information
- inSourceInfo.populatePointObjects(_track, inLoadedTrack.getNumPoints());
- _trackInfo.getFileInfo().addSource(inSourceInfo);
+ if (inSourceInfo != null)
+ {
+ // set source information
+ inSourceInfo.populatePointObjects(_track, inLoadedTrack.getNumPoints());
+ _trackInfo.getFileInfo().addSource(inSourceInfo);
+ }
}
else if (answer == JOptionPane.NO_OPTION)
{
_lastSavePosition = _undoStack.size();
_trackInfo.getSelection().clearAll();
_track.load(inLoadedTrack);
- inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
- _trackInfo.getFileInfo().replaceSource(inSourceInfo);
+ if (inSourceInfo != null)
+ {
+ // set source information
+ inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
+ _trackInfo.getFileInfo().replaceSource(inSourceInfo);
+ }
_trackInfo.getPhotoList().removeCorrelatedPhotos();
_trackInfo.getAudioList().removeCorrelatedAudios();
}
_lastSavePosition = _undoStack.size();
_trackInfo.getSelection().clearAll();
_track.load(inLoadedTrack);
- inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
- _trackInfo.getFileInfo().addSource(inSourceInfo);
+ if (inSourceInfo != null)
+ {
+ inSourceInfo.populatePointObjects(_track, _track.getNumPoints());
+ _trackInfo.getFileInfo().addSource(inSourceInfo);
+ }
}
// Update config before subscribers are told
- boolean isRegularLoad = (inSourceInfo.getFileType() != FILE_TYPE.GPSBABEL);
- Config.getRecentFileList().addFile(new RecentFile(inSourceInfo.getFile(), isRegularLoad));
+ if (inSourceInfo != null)
+ {
+ boolean isRegularLoad = (inSourceInfo.getFileType() != FILE_TYPE.GPSBABEL);
+ Config.getRecentFileList().addFile(new RecentFile(inSourceInfo.getFile(), isRegularLoad));
+ // Update status bar
+ UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile")
+ + " '" + inSourceInfo.getName() + "'");
+ }
UpdateMessageBroker.informSubscribers();
- // Update status bar
- UpdateMessageBroker.informSubscribers(I18nManager.getText("confirm.loadfile")
- + " '" + inSourceInfo.getName() + "'");
// update menu
_menuManager.informFileLoaded();
+ // recentre viewport on new file data
+ _viewport.recentreViewport();
+ // update main window title
+ updateTitle();
// Remove busy lock
_busyLoading = false;
// load next file if there's a queue
public void setCurrentMode(AppMode inMode) {
_appMode = inMode;
}
+
+ /** Update main window title **/
+ public void updateTitle() {
+ ArrayList<String> filenames = _trackInfo.getFileInfo().getFilenames();
+ if (filenames.size() > 0) {
+ _frame.setTitle(_titlePrefix + ": " + String.join(", ", filenames));
+ }
+ else
+ {
+ _frame.setTitle(_titlePrefix);
+ }
+ }
}
import tim.prune.function.DownloadOsmFunction;
import tim.prune.function.DuplicatePoint;
import tim.prune.function.FindWaypoint;
- import tim.prune.function.FullRangeDetails;
+ import tim.prune.function.ProjectPoint;
+ import tim.prune.function.ShowFullDetails;
import tim.prune.function.GetWikipediaFunction;
import tim.prune.function.HelpScreen;
import tim.prune.function.IgnoreExifThumb;
import tim.prune.function.InterpolateFunction;
- import tim.prune.function.PasteCoordinates;
import tim.prune.function.PhotoPopupFunction;
import tim.prune.function.PlayAudioFunction;
import tim.prune.function.RearrangePhotosFunction;
import tim.prune.function.RearrangeWaypointsFunction;
+import tim.prune.function.RemoveAltitudes;
import tim.prune.function.RemoveAudioFunction;
import tim.prune.function.RemovePhotoFunction;
import tim.prune.function.RotatePhoto;
import tim.prune.function.edit.PointNameEditor;
import tim.prune.function.estimate.EstimateTime;
import tim.prune.function.estimate.LearnParameters;
- import tim.prune.function.gpsies.GetGpsiesFunction;
- import tim.prune.function.gpsies.UploadGpsiesFunction;
import tim.prune.function.settings.SaveConfig;
import tim.prune.function.settings.SetAltitudeTolerance;
import tim.prune.function.settings.SetColours;
import tim.prune.function.settings.SetDisplaySettings;
+import tim.prune.function.settings.SetEarthdataAuthentication;
import tim.prune.function.settings.SetLanguage;
import tim.prune.function.settings.SetMapBgFunction;
import tim.prune.function.settings.SetPathsFunction;
import tim.prune.function.sew.SewTrackSegmentsFunction;
import tim.prune.function.sew.SplitSegmentsFunction;
-import tim.prune.function.srtm.DownloadSrtmFunction;
import tim.prune.function.srtm.LookupSrtmFunction;
import tim.prune.function.weather.GetWeatherForecastFunction;
import tim.prune.load.AudioLoader;
public static GenericFunction FUNCTION_IMPORTBABEL = null;
public static GenericFunction FUNCTION_SAVECONFIG = null;
public static GenericFunction FUNCTION_EDIT_WAYPOINT_NAME = null;
+ public static GenericFunction FUNCTION_PROJECT_POINT = null;
public static GenericFunction FUNCTION_REARRANGE_WAYPOINTS = null;
public static GenericFunction FUNCTION_SELECT_SEGMENT = null;
public static GenericFunction FUNCTION_SPLIT_SEGMENTS = null;
public static GenericFunction FUNCTION_DELETE_BY_DATE = null;
public static SingleNumericParameterFunction FUNCTION_INTERPOLATE = null;
public static GenericFunction FUNCTION_LOOKUP_SRTM = null;
- public static GenericFunction FUNCTION_DOWNLOAD_SRTM = null;
public static GenericFunction FUNCTION_NEARBY_WIKIPEDIA = null;
public static GenericFunction FUNCTION_SEARCH_WIKIPEDIA = null;
public static GenericFunction FUNCTION_SEARCH_OSMPOIS = null;
public static GenericFunction FUNCTION_DOWNLOAD_OSM = null;
public static GenericFunction FUNCTION_ADD_TIME_OFFSET = null;
public static GenericFunction FUNCTION_ADD_ALTITUDE_OFFSET = null;
+ public static GenericFunction FUNCTION_REMOVE_ALTITUDES = null;
public static GenericFunction FUNCTION_CONVERT_NAMES_TO_TIMES = null;
public static GenericFunction FUNCTION_DELETE_FIELD_VALUES = null;
- public static GenericFunction FUNCTION_PASTE_COORDINATES = null;
public static GenericFunction FUNCTION_FIND_WAYPOINT = null;
public static GenericFunction FUNCTION_DUPLICATE_POINT = null;
public static GenericFunction FUNCTION_CONNECT_TO_POINT = null;
public static GenericFunction FUNCTION_CHARTS = null;
public static GenericFunction FUNCTION_3D = null;
public static GenericFunction FUNCTION_DISTANCES = null;
- public static GenericFunction FUNCTION_FULL_RANGE_DETAILS = null;
+ public static GenericFunction FUNCTION_FULL_DETAILS = null;
public static GenericFunction FUNCTION_AUTOPLAY_TRACK = null;
public static GenericFunction FUNCTION_ESTIMATE_TIME = null;
public static GenericFunction FUNCTION_LEARN_ESTIMATION_PARAMS = null;
- public static GenericFunction FUNCTION_GET_GPSIES = null;
- public static GenericFunction FUNCTION_UPLOAD_GPSIES = null;
public static GenericFunction FUNCTION_GET_WEATHER_FORECAST = null;
public static GenericFunction FUNCTION_LOAD_AUDIO = null;
public static GenericFunction FUNCTION_REMOVE_AUDIO = null;
public static GenericFunction FUNCTION_SET_COLOURS = null;
public static GenericFunction FUNCTION_SET_LANGUAGE = null;
public static SingleNumericParameterFunction FUNCTION_SET_ALTITUDE_TOLERANCE = null;
+ public static GenericFunction FUNCTION_SET_EARTHDATA_AUTH = null;
public static GenericFunction FUNCTION_SET_TIMEZONE = null;
public static GenericFunction FUNCTION_HELP = null;
public static GenericFunction FUNCTION_SHOW_KEYS = null;
FUNCTION_IMPORTBABEL = new BabelLoadFromFile(inApp);
FUNCTION_SAVECONFIG = new SaveConfig(inApp);
FUNCTION_EDIT_WAYPOINT_NAME = new PointNameEditor(inApp);
+ FUNCTION_PROJECT_POINT = new ProjectPoint(inApp);
FUNCTION_REARRANGE_WAYPOINTS = new RearrangeWaypointsFunction(inApp);
FUNCTION_SELECT_SEGMENT = new SelectSegmentFunction(inApp);
FUNCTION_SPLIT_SEGMENTS = new SplitSegmentsFunction(inApp);
FUNCTION_DELETE_BY_DATE = new DeleteByDateFunction(inApp);
FUNCTION_INTERPOLATE = new InterpolateFunction(inApp);
FUNCTION_LOOKUP_SRTM = new LookupSrtmFunction(inApp);
- FUNCTION_DOWNLOAD_SRTM = new DownloadSrtmFunction(inApp);
FUNCTION_NEARBY_WIKIPEDIA = new GetWikipediaFunction(inApp);
FUNCTION_SEARCH_WIKIPEDIA = new SearchWikipediaNames(inApp);
FUNCTION_SEARCH_OSMPOIS = new SearchOsmPoisFunction(inApp);
FUNCTION_DOWNLOAD_OSM = new DownloadOsmFunction(inApp);
FUNCTION_ADD_TIME_OFFSET = new AddTimeOffset(inApp);
FUNCTION_ADD_ALTITUDE_OFFSET = new AddAltitudeOffset(inApp);
+ FUNCTION_REMOVE_ALTITUDES = new RemoveAltitudes(inApp);
FUNCTION_CONVERT_NAMES_TO_TIMES = new ConvertNamesToTimes(inApp);
FUNCTION_DELETE_FIELD_VALUES = new DeleteFieldValues(inApp);
- FUNCTION_PASTE_COORDINATES = new PasteCoordinates(inApp);
FUNCTION_FIND_WAYPOINT = new FindWaypoint(inApp);
FUNCTION_DUPLICATE_POINT = new DuplicatePoint(inApp);
FUNCTION_CONNECT_TO_POINT = new ConnectToPointFunction(inApp);
FUNCTION_CHARTS = new Charter(inApp);
FUNCTION_3D = new ShowThreeDFunction(inApp);
FUNCTION_DISTANCES = new DistanceFunction(inApp);
- FUNCTION_FULL_RANGE_DETAILS = new FullRangeDetails(inApp);
+ FUNCTION_FULL_DETAILS = new ShowFullDetails(inApp);
FUNCTION_AUTOPLAY_TRACK = new AutoplayFunction(inApp);
FUNCTION_ESTIMATE_TIME = new EstimateTime(inApp);
FUNCTION_LEARN_ESTIMATION_PARAMS = new LearnParameters(inApp);
- FUNCTION_GET_GPSIES = new GetGpsiesFunction(inApp);
- FUNCTION_UPLOAD_GPSIES = new UploadGpsiesFunction(inApp);
FUNCTION_GET_WEATHER_FORECAST = new GetWeatherForecastFunction(inApp);
FUNCTION_LOAD_AUDIO = new AudioLoader(inApp);
FUNCTION_REMOVE_AUDIO = new RemoveAudioFunction(inApp);
FUNCTION_SET_LANGUAGE = new SetLanguage(inApp);
FUNCTION_SET_ALTITUDE_TOLERANCE = new SetAltitudeTolerance(inApp);
FUNCTION_SET_TIMEZONE = new SelectTimezoneFunction(inApp);
+ FUNCTION_SET_EARTHDATA_AUTH = new SetEarthdataAuthentication(inApp);
FUNCTION_HELP = new HelpScreen(inApp);
FUNCTION_SHOW_KEYS = new ShowKeysScreen(inApp);
FUNCTION_ABOUT = new AboutScreen(inApp);
import java.io.FileNotFoundException;
import java.util.ArrayList;
import java.util.Locale;
+
import javax.swing.JFrame;
import javax.swing.JSplitPane;
import javax.swing.JToolBar;
+ import javax.swing.UIManager;
import javax.swing.WindowConstants;
import tim.prune.config.Config;
/**
* GpsPrune is a tool to visualize, edit, convert and prune GPS data
* Please see the included readme.txt or https://activityworkshop.net
- * This software is copyright activityworkshop.net 2006-2018 and made available through the Gnu GPL version 2.
+ * This software is copyright activityworkshop.net 2006-2020 and made available through the Gnu GPL version 2.
* For license details please see the included license.txt.
* GpsPrune is the main entry point to the application, including initialisation and launch
*/
public class GpsPrune
{
/** Version number of application, used in about screen and for version check */
- public static final String VERSION_NUMBER = "19.2";
+ public static final String VERSION_NUMBER = "20";
/** Build number, just used for about screen */
- public static final String BUILD_NUMBER = "363d";
+ public static final String BUILD_NUMBER = "378";
/** Static reference to App object */
private static App APP = null;
Config.setConfigString(Config.KEY_LANGUAGE_FILE, "");
}
}
+
+ // Set look-and-feel
+ try {
+ String windowStyle = Config.getConfigString(Config.KEY_WINDOW_STYLE);
+ UIManager.setLookAndFeel(windowStyle);
+ }
+ catch (Exception e) {}
+
// Set up the window and go
launch(dataFiles);
}
frame.setVisible(true);
// Set position of map/profile splitter
midSplit.setDividerLocation(0.75);
- // Update menu (only needed for recent file list)
- UpdateMessageBroker.informSubscribers();
// Make a full screen toggler
SidebarController fsc = new SidebarController(new Component[] {leftPanel, profileDisp, rightPanel},
public static final String KEY_POVRAY_FONT = "prune.povrayfont";
/** Key for the selected unit set */
public static final String KEY_UNITSET_KEY = "prune.unitsetkey";
+ /** Key for the selected coordinate display format */
+ public static final String KEY_COORD_DISPLAY_FORMAT = "prune.coorddisplay";
/** Key for index of map source */
public static final String KEY_MAPSOURCE_INDEX = "prune.mapsource";
/** Key for number of fixed map sources */
public static final String KEY_ANTIALIAS = "prune.antialias";
/** Key for kml track colour */
public static final String KEY_KML_TRACK_COLOUR = "prune.kmltrackcolour";
+ /** Key for window style (name of look-and-feel) */
+ public static final String KEY_WINDOW_STYLE = "prune.windowstyle";
/** Key for autosaving settings */
public static final String KEY_AUTOSAVE_SETTINGS = "prune.autosavesettings";
/** Key for recently used files */
public static final String KEY_WAYPOINT_ICON_SIZE = "prune.waypointiconsize";
/** Id of selected timezone */
public static final String KEY_TIMEZONE_ID = "prune.timezoneid";
+ /** Username/password to the Earthdata server for SRTM 1-arcsecond tiles */
+ public static final String KEY_EARTHDATA_AUTH = "prune.earthdataauth";
/** Initialise the default properties */
_unitSet = UnitSetLibrary.getUnitSet(_configValues.getProperty(KEY_UNITSET_KEY));
// Adjust map source index if necessary
adjustSelectedMap();
+ // Reset coord display format
+ setConfigInt(KEY_COORD_DISPLAY_FORMAT, 0);
if (loadFailed) {
throw new ConfigException();
props.put(KEY_ANTIALIAS, "1"); // antialias on by default
props.put(KEY_AUTOSAVE_SETTINGS, "0"); // autosave false by default
props.put(KEY_UNITSET_KEY, "unitset.kilometres"); // metric by default
+ props.put(KEY_COORD_DISPLAY_FORMAT, "0"); // original
props.put(KEY_HEIGHT_EXAGGERATION, "100"); // 100%, no exaggeration
props.put(KEY_TERRAIN_GRID_SIZE, "50");
props.put(KEY_ALTITUDE_TOLERANCE, "0"); // 0, all exact as before
return _configFile;
}
+ /**
+ * Set the file to which config was saved
+ */
+ public static void setConfigFile(File inFile)
+ {
+ _configFile = inFile;
+ }
+
/**
* @return config Properties object to allow all config values to be saved
*/
public static void updatePointColourer(PointColourer inColourer)
{
_pointColourer = inColourer;
- setConfigString(KEY_POINT_COLOURER, ColourerFactory.PointColourerToString(_pointColourer));
+ setConfigString(KEY_POINT_COLOURER, ColourerFactory.pointColourerToString(_pointColourer));
}
/**
*/
public void removeSource()
{
- _sources.remove(_sources.size()-1);
+ if (!_sources.isEmpty()) {
+ _sources.remove(_sources.size()-1);
+ }
}
/**
return "";
}
+ /**
+ * @return The source names
+ */
+ public ArrayList<String> getFilenames()
+ {
+ ArrayList<String> filenames = new ArrayList<String>();
+ for (SourceInfo source : _sources)
+ {
+ filenames.add(source.getName());
+ }
+ return filenames;
+ }
+
/**
* @param inIndex index number, starting from zero
* @return source info object
{
private JDialog _dialog = null;
private JRadioButton _addRadio = null, _subtractRadio = null;
- private WholeNumberField _dayField = null, _hourField = null;
- private WholeNumberField _minuteField = null;
+ private WholeNumberField _1024weekField = null, _dayField = null;
+ private WholeNumberField _hourField = null, _minuteField = null;
private JButton _okButton = null;
// Make a central panel with the text boxes
JPanel descPanel = new JPanel();
descPanel.setLayout(new GridLayout(0, 2));
+ descPanel.add(makeRightLabel("dialog.addtimeoffset.1024week"));
+ _1024weekField = new WholeNumberField(3);
+ descPanel.add(_1024weekField);
descPanel.add(makeRightLabel("dialog.addtimeoffset.days"));
- _dayField = new WholeNumberField(3);
+ _dayField = new WholeNumberField(4);
descPanel.add(_dayField);
descPanel.add(makeRightLabel("dialog.addtimeoffset.hours"));
_hourField = new WholeNumberField(3);
MouseAdapter mouseListener = new MouseAdapter() {
public void mouseReleased(java.awt.event.MouseEvent arg0) {
_okButton.setEnabled(getOffsetSecs() != 0L);
- };
+ }
};
+ _1024weekField.addKeyListener(keyListener);
_dayField.addKeyListener(keyListener);
_hourField.addKeyListener(keyListener);
_minuteField.addKeyListener(keyListener);
+ _1024weekField.addMouseListener(mouseListener);
_dayField.addMouseListener(mouseListener);
_hourField.addMouseListener(mouseListener);
_minuteField.addMouseListener(mouseListener);
{
long offsetSecs = _minuteField.getValue() * 60L
+ _hourField.getValue() * 60L * 60L
- + _dayField.getValue() * 60L * 60L * 24L;
+ + _dayField.getValue() * 60L * 60L * 24L
+ + _1024weekField.getValue() * 60L * 60L * 24L * 7L * 1024L;
if (_subtractRadio.isSelected()) {offsetSecs = -offsetSecs;}
return offsetSecs;
}
package tim.prune.function.srtm;
-import java.io.File;
-import java.io.FileInputStream;
-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.JOptionPane;
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.DataPoint;
import tim.prune.data.Field;
import tim.prune.data.Track;
import tim.prune.data.UnitSetLibrary;
import tim.prune.gui.ProgressDialog;
-import tim.prune.tips.TipManager;
import tim.prune.undo.UndoLookupSrtm;
/**
private Track _track = null;
/** Flag for whether this is a real track or a terrain one */
private boolean _normalTrack = true;
- /** Flag set when any tiles had to be downloaded (rather than just loaded locally) */
- private boolean _hadToDownload = false;
/** Flag to check whether this function is currently running or not */
private boolean _running = 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;
private void begin(Track inTrack, boolean inNormalTrack)
{
_running = true;
- _hadToDownload = false;
+ if (! SrtmDiskCache.ensureCacheIsUsable())
+ {
+ _app.showErrorMessage(getNameKey(), "error.cache.notthere");
+ }
if (_progress == null) {
_progress = new ProgressDialog(_parentFrame, getNameKey());
}
for (int i = 0; i < _track.getNumPoints(); i++)
{
// Consider points which don't have altitudes or have zero values
- if (!_track.getPoint(i).hasAltitude()
- || (overwriteZeros && _track.getPoint(i).getAltitude().getValue() == 0))
+ if (needsAltitude(_track.getPoint(i), overwriteZeros))
{
SrtmTile tile = new SrtmTile(_track.getPoint(i));
boolean alreadyGot = false;
lookupValues(tileList, overwriteZeros);
// Finished
_running = false;
- // Show tip if lots of online lookups were necessary
- if (_hadToDownload) {
- _app.showTip(TipManager.Tip_DownloadSrtm);
- }
}
+ /**
+ * true if we need to set the altitude of this point
+ */
+ private boolean needsAltitude(DataPoint point, boolean overwriteZeros)
+ {
+ if (!point.hasAltitude())
+ {
+ return true;
+ }
+ if (overwriteZeros && point.getAltitude().getValue() == 0)
+ {
+ return true;
+ }
+ return false;
+ }
/**
* Lookup the values from SRTM data
_progress.setMaximum(inTileList.size());
_progress.setValue(0);
}
- String errorMessage = null;
- // Get urls for each tile
- URL[] urls = TileFinder.getUrls(inTileList);
- for (int t=0; t<inTileList.size() && !_progress.isCancelled() && urls != null; t++)
+ String errorMessage = "";
+ for (int t=0; t<inTileList.size() && !_progress.isCancelled(); t++)
{
- if (urls[t] != null)
+ SrtmTile tile = inTileList.get(t);
+ SrtmSource srtmSource = tile.findBestCachedSource();
+
+ if (srtmSource == null)
{
- SrtmTile tile = inTileList.get(t);
- try
- {
- // Set progress
- _progress.setValue(t);
- final int ARRLENGTH = 1201 * 1201;
- int[] heights = new int[ARRLENGTH];
- // Open zipinputstream on url and check size
- ZipInputStream inStream = getStreamToHgtFile(urls[t]);
- boolean entryOk = false;
- if (inStream != null)
- {
- ZipEntry entry = inStream.getNextEntry();
- entryOk = (entry != null && 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();
- }
+ errorMessage += "Tile "+tile.getTileName()+" not in cache!\n";
+ continue;
+ }
- if (entryOk)
- {
- numAltitudesFound += applySrtmTileToWholeTrack(tile, heights, inOverwriteZeros);
- }
- }
- catch (IOException ioe) {
- errorMessage = ioe.getClass().getName() + " - " + ioe.getMessage();
- }
+ // Set progress
+ _progress.setValue(t);
+
+ int[] heights;
+ try {
+ heights = srtmSource.getTileHeights(tile);
+ }
+ catch (SrtmSourceException e)
+ {
+ errorMessage += e.getMessage();
+ e.printStackTrace();
+ continue;
}
- // 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 (needsAltitude(point, inOverwriteZeros))
- {
- if (new SrtmTile(point).equals(tile))
- {
- double x = (point.getLongitude().getDouble() - tile.getLongitude()) * (rowSize - 1);
- double y = rowSize - (point.getLatitude().getDouble() - tile.getLatitude()) * (rowSize - 1);
- int idx1 = ((int)y)*rowSize + (int)x;
- try
- {
- int[] fouralts = {heights[idx1], heights[idx1+1], heights[idx1-rowSize], heights[idx1-rowSize+1]};
- 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;
- }
- // Special case for terrain tracks, don't interpolate voids yet
- if (!_normalTrack && numVoids > 0) {
- altitude = VOID_VAL;
- }
- if (altitude != VOID_VAL)
- {
- point.setFieldValue(Field.ALTITUDE, ""+altitude, false);
- // depending on settings, this value may have been added as feet, we need to force metres
- point.getAltitude().reset(new Altitude((int)altitude, UnitSetLibrary.UNITS_METRES));
- numAltitudesFound++;
- }
- }
- catch (ArrayIndexOutOfBoundsException obe) {
- errorMessage += "Point not in tile? lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1+"\n";
- }
- }
- }
- }
+ int rowSize = srtmSource.getRowSize(tile);
+ if (rowSize <= 0)
+ {
+ errorMessage += "Tile "+tile.getTileName()+" is corrupted";
+ }
+
++ numAltitudesFound += applySrtmTimeToWholeTrack(tile, heights, rowSize, inOverwriteZeros);
}
_progress.dispose();
return;
}
+ if (! errorMessage.equals("")) {
+ _app.showErrorMessageNoLookup(getNameKey(), errorMessage);
+ return;
+ }
if (numAltitudesFound > 0)
{
// Inform app including undo information
I18nManager.getTextWithNumber("confirm.lookupsrtm", numAltitudesFound));
}
}
- else if (errorMessage != null) {
- _app.showErrorMessageNoLookup(getNameKey(), errorMessage);
- }
else if (inTileList.size() > 0) {
_app.showErrorMessage(getNameKey(), "error.lookupsrtm.nonefound");
}
}
}
- /**
- * See whether the SRTM file is already available locally first, then try online
- * @param inUrl URL for online resource
- * @return ZipInputStream either on the local file or on the downloaded zip file
- */
- private ZipInputStream getStreamToHgtFile(URL inUrl)
- throws IOException
- {
- String diskCachePath = Config.getConfigString(Config.KEY_DISK_CACHE);
- if (diskCachePath != null)
- {
- File srtmDir = new File(diskCachePath, "srtm");
- if (srtmDir.exists() && srtmDir.isDirectory() && srtmDir.canRead())
- {
- File srtmFile = new File(srtmDir, new File(inUrl.getFile()).getName());
- if (srtmFile.exists() && srtmFile.isFile() && srtmFile.canRead()
- && srtmFile.length() > 400)
- {
- // System.out.println("Lookup: Using file " + srtmFile.getAbsolutePath());
- // File found, use this one
- return new ZipInputStream(new FileInputStream(srtmFile));
- }
- }
- }
- // System.out.println("Lookup: Trying online: " + inUrl.toString());
- _hadToDownload = true;
- // MAYBE: Only download if we're in online mode?
- return new ZipInputStream(inUrl.openStream());
- }
-
+ /**
+ * Given the height data read in from file, apply the given tile to all points
+ * in the track with missing altitude
+ * @param inTile tile being applied
+ * @param inHeights height data read in from file
+ * @param inOverwriteZeros true to overwrite zero altitude values
+ * @return number of altitudes found
+ */
- private int applySrtmTileToWholeTrack(SrtmTile inTile, int[] inHeights, boolean inOverwriteZeros)
++ private int applySrtmTimeToWholeTrack(SrtmTile inTile, int[] inHeights, int inRowSize, boolean inOverwriteZeros)
+ {
+ int numAltitudesFound = 0;
+ // 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()
- || (inOverwriteZeros && point.getAltitude().getValue() == 0))
++ if (needsAltitude(point, inOverwriteZeros))
+ {
+ if (new SrtmTile(point).equals(inTile))
+ {
- double x = (point.getLongitude().getDouble() - inTile.getLongitude()) * 1200;
- double y = 1201 - (point.getLatitude().getDouble() - inTile.getLatitude()) * 1200;
- int idx1 = ((int)y)*1201 + (int)x;
++ double x = (point.getLongitude().getDouble() - inTile.getLongitude()) * (inRowSize - 1);
++ double y = inRowSize - (point.getLatitude().getDouble() - inTile.getLatitude()) * (inRowSize - 1);
++ int idx1 = ((int)y)*inRowSize + (int)x;
+ try
+ {
- int[] fouralts = {inHeights[idx1], inHeights[idx1+1], inHeights[idx1-1201], inHeights[idx1-1200]};
++ int[] fouralts = {inHeights[idx1], inHeights[idx1+1], inHeights[idx1-inRowSize], inHeights[idx1-inRowSize+1]};
+ 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;
++ 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;
+ }
+ // Special case for terrain tracks, don't interpolate voids yet
+ if (!_normalTrack && numVoids > 0) {
+ altitude = VOID_VAL;
+ }
+ if (altitude != VOID_VAL)
+ {
+ point.setFieldValue(Field.ALTITUDE, ""+altitude, false);
+ // depending on settings, this value may have been added as feet, we need to force metres
+ point.getAltitude().reset(new Altitude((int)altitude, UnitSetLibrary.UNITS_METRES));
+ numAltitudesFound++;
+ }
+ }
+ catch (ArrayIndexOutOfBoundsException obe) {
- // System.err.println("lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1);
++ System.err.println("Point not in tile? lat=" + point.getLatitude().getDouble() + ", x=" + x + ", y=" + y + ", idx=" + idx1+"\n");
+ }
+ }
+ }
+ }
+ return numAltitudesFound;
+ }
+
/**
* Perform a bilinear interpolation on the given altitude array
* @param inAltitudes array of four altitude values on corners of square (bl, br, tl, tr)
import tim.prune.data.Track;
import tim.prune.data.TrackInfo;
import tim.prune.function.ChooseSingleParameter;
+ import tim.prune.function.PasteCoordinateList;
+ import tim.prune.function.PasteCoordinates;
+ import tim.prune.function.PlusCodeFunction;
import tim.prune.function.SearchOpenCachingDeFunction;
import tim.prune.function.browser.UrlGenerator;
import tim.prune.function.browser.WebMapFunction;
import tim.prune.function.search.SearchMapillaryFunction;
+import tim.prune.function.srtm.DownloadSrtmFunction;
+import tim.prune.function.srtm.SrtmGl1Source;
+import tim.prune.function.srtm.Srtm3Source;
+import tim.prune.function.srtm.SrtmViewfinderSource;
+ import tim.prune.function.settings.SaveConfig;
/**
* Class to manage the menu bar and tool bar,
private JMenuItem _selectEndItem = null;
private JMenuItem _findWaypointItem = null;
private JMenuItem _duplicatePointItem = null;
+ private JMenuItem _projectPointItem = null;
private JMenuItem _reverseItem = null;
private JMenuItem _addTimeOffsetItem = null;
private JMenuItem _addAltitudeOffsetItem = null;
+ private JMenuItem _removeAltitudesItem = null;
private JMenuItem _mergeSegmentsItem = null;
private JMenuItem _rearrangeWaypointsItem = null;
private JMenuItem _splitSegmentsItem = null;
private JMenu _browserMapMenu = null;
private JMenuItem _routingGraphHopperItem = null;
private JMenuItem _chartItem = null;
- private JMenuItem _getGpsiesItem = null;
- private JMenuItem _uploadGpsiesItem = null;
private JMenuItem _lookupSrtmItem = null;
- private JMenuItem _downloadSrtmItem = null;
+ private JMenu _downloadSrtmMenu = null;
private JMenuItem _nearbyWikipediaItem = null;
private JMenuItem _nearbyOsmPoiItem = null;
private JMenuItem _showPeakfinderItem = null;
private JMenuItem _downloadOsmItem = null;
private JMenuItem _getWeatherItem = null;
private JMenuItem _distanceItem = null;
- private JMenuItem _fullRangeDetailsItem = null;
+ private JMenuItem _viewFullDetailsItem = null;
private JMenuItem _estimateTimeItem = null;
private JMenuItem _learnEstimationParams = null;
private JMenuItem _autoplayTrack = null;
// SRTM
_lookupSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_LOOKUP_SRTM, false);
onlineMenu.add(_lookupSrtmItem);
- _downloadSrtmItem = makeMenuItem(FunctionLibrary.FUNCTION_DOWNLOAD_SRTM, false);
- onlineMenu.add(_downloadSrtmItem);
+ // Download SRTM sub-menu
+ _downloadSrtmMenu = new JMenu(I18nManager.getText("function.downloadsrtm"));
+ _downloadSrtmMenu.setEnabled(false);
+ JMenuItem downloadStrmGl1Item = makeMenuItem(new DownloadSrtmFunction(_app, new SrtmGl1Source()));
+ _downloadSrtmMenu.add(downloadStrmGl1Item);
+ JMenuItem downloadStrmViewfinderItem = makeMenuItem(new DownloadSrtmFunction(_app, new SrtmViewfinderSource()));
+ _downloadSrtmMenu.add(downloadStrmViewfinderItem);
+ JMenuItem downloadStrm3Item = makeMenuItem(new DownloadSrtmFunction(_app, new Srtm3Source()));
+ _downloadSrtmMenu.add(downloadStrm3Item);
+ onlineMenu.add(_downloadSrtmMenu);
- // Get gpsies tracks
- _getGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_GET_GPSIES, false);
- onlineMenu.add(_getGpsiesItem);
- // Upload to gpsies
- _uploadGpsiesItem = makeMenuItem(FunctionLibrary.FUNCTION_UPLOAD_GPSIES, false);
- onlineMenu.add(_uploadGpsiesItem);
-
onlineMenu.addSeparator();
// browser submenu
_browserMapMenu = new JMenu(I18nManager.getText("menu.view.browser"));
rangeMenu.add(_addTimeOffsetItem);
_addAltitudeOffsetItem = makeMenuItem(FunctionLibrary.FUNCTION_ADD_ALTITUDE_OFFSET, false);
rangeMenu.add(_addAltitudeOffsetItem);
+ _removeAltitudesItem = makeMenuItem(FunctionLibrary.FUNCTION_REMOVE_ALTITUDES, false);
+ rangeMenu.add(_removeAltitudesItem);
_mergeSegmentsItem = new JMenuItem(I18nManager.getText("menu.range.mergetracksegments"));
_mergeSegmentsItem.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
// duplicate current point
_duplicatePointItem = makeMenuItem(FunctionLibrary.FUNCTION_DUPLICATE_POINT, false);
pointMenu.add(_duplicatePointItem);
+ // project current point
+ _projectPointItem = makeMenuItem(FunctionLibrary.FUNCTION_PROJECT_POINT, false);
+ pointMenu.add(_projectPointItem);
// paste coordinates function
- JMenuItem pasteCoordsItem = makeMenuItem(FunctionLibrary.FUNCTION_PASTE_COORDINATES);
+ JMenuItem pasteCoordsItem = makeMenuItem(new PasteCoordinates(_app));
pointMenu.add(pasteCoordsItem);
+ JMenuItem pasteCoordsListItem = makeMenuItem(new PasteCoordinateList(_app));
+ pointMenu.add(pasteCoordsListItem);
+ // pluscodes function
+ JMenuItem plusCodeItem = makeMenuItem(new PlusCodeFunction(_app));
+ pointMenu.add(plusCodeItem);
menubar.add(pointMenu);
// Add view menu
_distanceItem = makeMenuItem(FunctionLibrary.FUNCTION_DISTANCES, false);
viewMenu.add(_distanceItem);
// full range details
- _fullRangeDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_RANGE_DETAILS, false);
- viewMenu.add(_fullRangeDetailsItem);
+ _viewFullDetailsItem = makeMenuItem(FunctionLibrary.FUNCTION_FULL_DETAILS, false);
+ viewMenu.add(_viewFullDetailsItem);
// estimate time
_estimateTimeItem = makeMenuItem(FunctionLibrary.FUNCTION_ESTIMATE_TIME, false);
viewMenu.add(_estimateTimeItem);
settingsMenu.add(makeMenuItem(new ChooseSingleParameter(_app, FunctionLibrary.FUNCTION_SET_ALTITUDE_TOLERANCE)));
// Set timezone
settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_TIMEZONE));
+ // Set Earthdata authentication
+ settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SET_EARTHDATA_AUTH));
settingsMenu.addSeparator();
// Save configuration
settingsMenu.add(makeMenuItem(FunctionLibrary.FUNCTION_SAVECONFIG));
_autosaveSettingsCheckbox.setSelected(Config.getConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS));
_autosaveSettingsCheckbox.addActionListener(new ActionListener() {
public void actionPerformed(ActionEvent e) {
- Config.setConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS, _autosaveSettingsCheckbox.isSelected());
+ final boolean autosaveOn = _autosaveSettingsCheckbox.isSelected();
+ Config.setConfigBoolean(Config.KEY_AUTOSAVE_SETTINGS, autosaveOn);
+ // Maybe want to save config?
+ new SaveConfig(_app).autosaveSwitched(autosaveOn);
}
});
settingsMenu.add(_autosaveSettingsCheckbox);
_markRectangleItem.setEnabled(hasData);
_markUphillLiftsItem.setEnabled(hasData && _track.hasAltitudeData());
_deleteMarkedPointsItem.setEnabled(hasData && _track.hasMarkedPoints());
- _rearrangeWaypointsItem.setEnabled(hasData && _track.hasTrackPoints() && _track.hasWaypoints());
+ _rearrangeWaypointsItem.setEnabled(hasData && _track.hasWaypoints() && _track.getNumPoints() > 1);
final boolean hasSeveralTrackPoints = hasData && _track.hasTrackPoints() && _track.getNumPoints() > 3;
_splitSegmentsItem.setEnabled(hasSeveralTrackPoints);
_sewSegmentsItem.setEnabled(hasSeveralTrackPoints);
_browserMapMenu.setEnabled(hasData);
_distanceItem.setEnabled(hasData);
_autoplayTrack.setEnabled(hasData && _track.getNumPoints() > 3);
- _getGpsiesItem.setEnabled(hasData);
- _uploadGpsiesItem.setEnabled(hasData && _track.hasTrackPoints());
_lookupSrtmItem.setEnabled(hasData);
_nearbyWikipediaItem.setEnabled(hasData);
_nearbyOsmPoiItem.setEnabled(hasData);
_getWeatherItem.setEnabled(hasData);
_findWaypointItem.setEnabled(hasData && _track.hasWaypoints());
// have we got a cache?
- _downloadSrtmItem.setEnabled(hasData && Config.getConfigString(Config.KEY_DISK_CACHE) != null);
+ _downloadSrtmMenu.setEnabled(hasData && Config.getConfigString(Config.KEY_DISK_CACHE) != null);
// have we got any timestamps?
_deleteByDateItem.setEnabled(hasData && _track.hasData(Field.TIMESTAMP));
_selectEndItem.setEnabled(hasPoint);
_selectEndButton.setEnabled(hasPoint);
_duplicatePointItem.setEnabled(hasPoint);
+ _projectPointItem.setEnabled(hasPoint);
_showPeakfinderItem.setEnabled(hasPoint);
_showGeohackItem.setEnabled(hasPoint);
_searchOpencachingDeItem.setEnabled(hasPoint);
_reverseItem.setEnabled(hasRange);
_addTimeOffsetItem.setEnabled(hasRange);
_addAltitudeOffsetItem.setEnabled(hasRange);
+ _removeAltitudesItem.setEnabled(hasRange);
_convertNamesToTimesItem.setEnabled(hasRange && _track.hasWaypoints());
_deleteFieldValuesItem.setEnabled(hasRange);
- _fullRangeDetailsItem.setEnabled(hasRange);
+ _viewFullDetailsItem.setEnabled(hasRange || hasPoint);
_estimateTimeItem.setEnabled(hasRange);
_learnEstimationParams.setEnabled(hasData && _track.hasTrackPoints() && _track.hasData(Field.TIMESTAMP)
&& _track.hasAltitudeData());
/**
* Class to provide access to current viewport
* The point of this class is to decouple the view from the MapCanvas object
- * so that when the GetGpsies function needs to know the area currently viewed, it doesn't
+ * so that when a search function needs to know the area currently viewed, it doesn't
* need to have a direct connection to the MapCanvas. Instead it asks the App for the viewport,
* which is then able to get the map position from the MapCanvas.
* I'm still not sure whether this is ugly or not, but it's more efficient than constantly listening.
double maxLon = MapUtils.getLongitudeFromX(mapPosition.getXFromPixels(width, width));
return new double[] {minLat, minLon, maxLat, maxLon};
}
+
+ /**
+ * Recentre the viewport on the data
+ */
+ public void recentreViewport()
+ {
+ _mapCanvas.zoomToFit();
+ }
}
WpIconDefinition _waypointIconDefinition = null;
/** Constant for click sensitivity when selecting nearest point */
- private static final int CLICK_SENSITIVITY = 10;
+ private static final int CLICK_SENSITIVITY = 30;
/** Constant for pan distance from key presses */
private static final int PAN_DISTANCE = 20;
/** Constant for pan distance from autopan */
// add control panels to this one
setLayout(new BorderLayout());
- _topPanel.setVisible(false);
- _sidePanel.setVisible(false);
+ _topPanel.setVisible(true);
+ _sidePanel.setVisible(true);
add(_topPanel, BorderLayout.NORTH);
add(_sidePanel, BorderLayout.WEST);
add(_scaleBar, BorderLayout.SOUTH);
/**
* Zoom to fit the current data area
*/
- private void zoomToFit()
+ public void zoomToFit()
{
+ int maxZoom = (_track.getNumPoints() == 0)?2:_tileManager.getMaxZoomLevel();
_latRange = _track.getLatRange();
_lonRange = _track.getLonRange();
_xRange = new DoubleRange(MapUtils.getXFromLongitude(_lonRange.getMinimum()),
MapUtils.getXFromLongitude(_lonRange.getMaximum()));
_yRange = new DoubleRange(MapUtils.getYFromLatitude(_latRange.getMinimum()),
MapUtils.getYFromLatitude(_latRange.getMaximum()));
- _mapPosition.zoomToXY(_xRange.getMinimum(), _xRange.getMaximum(), _yRange.getMinimum(), _yRange.getMaximum(),
- getWidth(), getHeight());
+ _mapPosition.zoomToXY(
+ _xRange.getMinimum(), _xRange.getMaximum(),
+ _yRange.getMinimum(), _yRange.getMaximum(),
+ getWidth(), getHeight(), maxZoom);
}
if (_mapImage != null && (_mapImage.getWidth() != getWidth() || _mapImage.getHeight() != getHeight())) {
_mapImage = null;
}
- if (_track.getNumPoints() > 0)
+ // Check for autopan if enabled / necessary
+ if (_autopanCheckBox.isSelected())
{
- // Check for autopan if enabled / necessary
- if (_autopanCheckBox.isSelected())
+ int selectedPoint = _selection.getCurrentPointIndex();
+ if (selectedPoint >= 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint)
{
- int selectedPoint = _selection.getCurrentPointIndex();
- if (selectedPoint >= 0 && _dragFromX == -1 && selectedPoint != _prevSelectedPoint)
- {
- autopanToPoint(selectedPoint);
- }
- _prevSelectedPoint = selectedPoint;
+ autopanToPoint(selectedPoint);
}
+ _prevSelectedPoint = selectedPoint;
+ }
- // Draw the map contents if necessary
- if (_mapImage == null || _recalculate)
- {
- paintMapContents();
- _scaleBar.updateScale(_mapPosition.getZoom(), _mapPosition.getYFromPixels(0, 0));
- }
- // Draw the prepared image onto the panel
- if (_mapImage != null) {
- inG.drawImage(_mapImage, 0, 0, getWidth(), getHeight(), null);
- }
+ // Draw the map contents if necessary
+ if (_mapImage == null || _recalculate)
+ {
+ paintMapContents();
+ _scaleBar.updateScale(_mapPosition.getZoom(), _mapPosition.getYFromPixels(0, 0));
+ }
+ // Draw the prepared image onto the panel
+ if (_mapImage != null) {
+ inG.drawImage(_mapImage, 0, 0, getWidth(), getHeight(), null);
+ }
- switch (_drawMode)
- {
- case MODE_DRAG_POINT:
- drawDragLines(inG, _selection.getCurrentPointIndex()-1, _selection.getCurrentPointIndex()+1);
- break;
+ switch (_drawMode)
+ {
+ case MODE_DRAG_POINT:
+ drawDragLines(inG, _selection.getCurrentPointIndex()-1, _selection.getCurrentPointIndex()+1);
+ break;
- case MODE_CREATE_MIDPOINT:
- drawDragLines(inG, _clickedPoint-1, _clickedPoint);
- break;
+ case MODE_CREATE_MIDPOINT:
+ drawDragLines(inG, _clickedPoint-1, _clickedPoint);
+ break;
- case MODE_ZOOM_RECT:
- case MODE_MARK_RECTANGLE:
- if (_dragFromX != -1 && _dragFromY != -1)
- {
- // Draw the zoom rectangle if necessary
- inG.setColor(Color.RED);
- inG.drawLine(_dragFromX, _dragFromY, _dragFromX, _dragToY);
- inG.drawLine(_dragFromX, _dragFromY, _dragToX, _dragFromY);
- inG.drawLine(_dragToX, _dragFromY, _dragToX, _dragToY);
- inG.drawLine(_dragFromX, _dragToY, _dragToX, _dragToY);
- }
- break;
-
- case MODE_DRAW_POINTS_CONT:
- // draw line to mouse position to show drawing mode
- inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_POINT));
- int prevIndex = _track.getNumPoints()-1;
- int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(prevIndex));
- int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(prevIndex));
- inG.drawLine(px, py, _dragToX, _dragToY);
- break;
- }
- }
- else
- {
- inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_BACKGROUND));
- inG.fillRect(0, 0, getWidth(), getHeight());
- inG.setColor(COLOR_MESSAGES);
- inG.drawString(I18nManager.getText("display.nodata"), 50, getHeight()/2);
- _scaleBar.updateScale(-1, 0);
+ case MODE_ZOOM_RECT:
+ case MODE_MARK_RECTANGLE:
+ if (_dragFromX != -1 && _dragFromY != -1)
+ {
+ // Draw the zoom rectangle if necessary
+ inG.setColor(Color.RED);
+ inG.drawLine(_dragFromX, _dragFromY, _dragFromX, _dragToY);
+ inG.drawLine(_dragFromX, _dragFromY, _dragToX, _dragFromY);
+ inG.drawLine(_dragToX, _dragFromY, _dragToX, _dragToY);
+ inG.drawLine(_dragFromX, _dragToY, _dragToX, _dragToY);
+ }
+ break;
+
+ case MODE_DRAW_POINTS_CONT:
+ // draw line to mouse position to show drawing mode
+ inG.setColor(Config.getColourScheme().getColour(ColourScheme.IDX_POINT));
+ int prevIndex = _track.getNumPoints()-1;
+ int px = getWidth() / 2 + _mapPosition.getXFromCentre(_track.getX(prevIndex));
+ int py = getHeight() / 2 + _mapPosition.getYFromCentre(_track.getY(prevIndex));
+ inG.drawLine(px, py, _dragToX, _dragToY);
+ break;
}
// Draw slider etc on top
paintChildren(inG);
final double pointSeparationSqd = (prevX-px) * (prevX-px) + (prevY-py) * (prevY-py);
if (pointSeparationSqd > pointSeparationForArrowsSqd)
{
- final double midX = (prevX + px) / 2;
- final double midY = (prevY + py) / 2;
+ final double midX = (prevX + px) / 2.0;
+ final double midY = (prevY + py) / 2.0;
final boolean midPointVisible = midX >= 0 && midX < winWidth && midY >= 0 && midY < winHeight;
if (midPointVisible)
{
*/
public void mouseClicked(MouseEvent inE)
{
- if (_track != null && _track.getNumPoints() > 0)
+ // select point if it's a left-click
+ if (!inE.isMetaDown())
{
- // select point if it's a left-click
- if (!inE.isMetaDown())
+ if (inE.getClickCount() == 1)
{
- if (inE.getClickCount() == 1)
+ // single click
+ if (_drawMode == MODE_DEFAULT)
{
- // single click
- if (_drawMode == MODE_DEFAULT)
+ int pointIndex = _clickedPoint;
+ if (pointIndex == INDEX_UNKNOWN)
{
- int pointIndex = _clickedPoint;
- if (pointIndex == INDEX_UNKNOWN)
- {
- // index hasn't been calculated yet
- pointIndex = _track.getNearestPointIndex(
- _mapPosition.getXFromPixels(inE.getX(), getWidth()),
- _mapPosition.getYFromPixels(inE.getY(), getHeight()),
- _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false);
- }
- // Extend selection for shift-click
- if (inE.isShiftDown()) {
- _trackInfo.extendSelection(pointIndex);
- }
- else {
- _trackInfo.selectPoint(pointIndex);
- }
+ // index hasn't been calculated yet
+ pointIndex = _track.getNearestPointIndex(
+ _mapPosition.getXFromPixels(inE.getX(), getWidth()),
+ _mapPosition.getYFromPixels(inE.getY(), getHeight()),
+ _mapPosition.getBoundsFromPixels(CLICK_SENSITIVITY), false);
}
- else if (_drawMode == MODE_DRAW_POINTS_START)
- {
- _app.createPoint(createPointFromClick(inE.getX(), inE.getY()));
- _dragToX = inE.getX();
- _dragToY = inE.getY();
- _drawMode = MODE_DRAW_POINTS_CONT;
+ // Extend selection for shift-click
+ if (inE.isShiftDown()) {
+ _trackInfo.extendSelection(pointIndex);
}
- else if (_drawMode == MODE_DRAW_POINTS_CONT)
- {
- DataPoint point = createPointFromClick(inE.getX(), inE.getY());
- _app.createPoint(point, false); // not a new segment
+ else {
+ _trackInfo.selectPoint(pointIndex);
}
}
- else if (inE.getClickCount() == 2)
+ else if (_drawMode == MODE_DRAW_POINTS_START)
{
- // double click
- if (_drawMode == MODE_DEFAULT) {
- panMap(inE.getX() - getWidth()/2, inE.getY() - getHeight()/2);
- zoomIn();
- }
- else if (_drawMode == MODE_DRAW_POINTS_START || _drawMode == MODE_DRAW_POINTS_CONT) {
- _drawMode = MODE_DEFAULT;
- }
+ _app.createPoint(createPointFromClick(inE.getX(), inE.getY()));
+ _dragToX = inE.getX();
+ _dragToY = inE.getY();
+ _drawMode = MODE_DRAW_POINTS_CONT;
+ }
+ else if (_drawMode == MODE_DRAW_POINTS_CONT)
+ {
+ DataPoint point = createPointFromClick(inE.getX(), inE.getY());
+ _app.createPoint(point, false); // not a new segment
}
}
- else
+ else if (inE.getClickCount() == 2)
{
- // show the popup menu for right-clicks
- _popupMenuX = inE.getX();
- _popupMenuY = inE.getY();
- _popup.show(this, _popupMenuX, _popupMenuY);
+ // double click
+ if (_drawMode == MODE_DEFAULT) {
+ panMap(inE.getX() - getWidth()/2, inE.getY() - getHeight()/2);
+ zoomIn();
+ }
+ else if (_drawMode == MODE_DRAW_POINTS_START || _drawMode == MODE_DRAW_POINTS_CONT) {
+ _drawMode = MODE_DEFAULT;
+ }
}
}
+ else
+ {
+ // show the popup menu for right-clicks
+ _popupMenuX = inE.getX();
+ _popupMenuY = inE.getY();
+ _popup.show(this, _popupMenuX, _popupMenuY);
+ }
// Reset app mode
_app.setCurrentMode(App.AppMode.NORMAL);
if (_drawMode == MODE_MARK_RECTANGLE) _drawMode = MODE_DEFAULT;
}
}
repaint();
- // enable or disable components
- boolean hasData = _track.getNumPoints() > 0;
- _topPanel.setVisible(hasData);
- _sidePanel.setVisible(hasData);
// grab focus for the key presses
this.requestFocus();
}
* @return true if zoom is too high for tiles
*/
public boolean isOverzoomed()
+ {
+ return _zoom > getMaxZoomLevel();
+ }
+
+ /**
+ * @return the maximum useable zoom level for tiles
+ */
+ public int getMaxZoomLevel()
{
// Ask current map source what maximum zoom is
int maxZoom = (_mapSource == null?0:_mapSource.getMaxZoomLevel());
- return (_zoom > maxZoom);
+ return maxZoom;
+
}
/**
tempCache = _tempCaches[inLayer]; // Should probably guard array indexes here
tileImage = tempCache.getTile(inX, inY);
if (tileImage != null) {
+ //System.out.println("Got tile from memory: " + inX + ", " + inY);
return tileImage;
}
}
try
{
URL tileUrl = new URL(_mapSource.makeURL(inLayer, _zoom, inX, inY));
- //System.out.println("Trying to fetch: " + tileUrl);
if (useDisk)
{
DiskTileCacher.saveTile(tileUrl, diskCachePath,
function.deletebydate=Delete points by date
function.addtimeoffset=Add time offset
function.addaltitudeoffset=Add altitude offset
+function.removealtitudes=Remove altitudes
function.findwaypoint=Find waypoint
function.rearrangewaypoints=Rearrange waypoints
function.convertnamestotimes=Convert waypoint names to times
function.deletefieldvalues=Delete field values
- function.pastecoordinates=Enter new coordinates
+ function.pastecoordinates=Enter point coordinates
+ function.pastecoordinatelist=Enter list of coordinates
+ function.enterpluscode=Enter pluscode
function.charts=Charts
function.show3d=Three-D view
function.distances=Distances
- function.fullrangedetails=Full range details
+ function.viewfulldetails=Full details
function.estimatetime=Estimate time
function.learnestimationparams=Learn time estimation parameters
function.autoplay=Autoplay track
function.splitsegments=Split track into segments
function.sewsegments=Sew track segments together
function.createmarkerwaypoints=Create marker waypoints
- function.getgpsies=Get Gpsies tracks
- function.uploadgpsies=Upload track to Gpsies
function.lookupsrtm=Get altitudes from SRTM
function.downloadsrtm=Download SRTM tiles
+function.downloadsrtm.SRTMGL1_v003=SRTM 1 arc-second tiles
+function.downloadsrtm.SRTMGL1_v003.needsetup=An Earthdata account is necessary to download SRTM 1 arc-second tiles
+function.downloadsrtm.SRTM3_v21=SRTM 3 arc-second tiles
+function.downloadsrtm.SRTM_Viewfinder=Viewfinderpanoramas.org data
function.getwikipedia=Get nearby Wikipedia articles
function.searchwikipedianames=Search Wikipedia by name
function.searchosmpois=Get nearby OSM points
function.mapillary=Search for photos in Mapillary
function.downloadosm=Download OSM data for area
function.duplicatepoint=Duplicate point
+ function.projectpoint=Project point
function.connecttopoint=Connect to point
function.disconnectfrompoint=Disconnect from point
function.removephoto=Remove photo
function.getweatherforecast=Get weather forecast
function.setaltitudetolerance=Set altitude tolerance
function.selecttimezone=Set timezone
+function.setearthdataauthentication=Set Earthdata authentication
# Dialogs
dialog.exit.confirm.title=Exit GpsPrune
dialog.pointnameedit.titlecase=Title Case
dialog.addtimeoffset.add=Add time
dialog.addtimeoffset.subtract=Subtract time
+dialog.addtimeoffset.1024week=1024-week block
dialog.addtimeoffset.days=Days
dialog.addtimeoffset.hours=Hours
dialog.addtimeoffset.minutes=Minutes
dialog.gpsies.description=Description
dialog.gpsies.nodescription=No description
dialog.gpsies.nonefound=No tracks found
- dialog.gpsies.username=Gpsies username
- dialog.gpsies.password=Gpsies password
- dialog.gpsies.keepprivate=Keep track private
- dialog.gpsies.confirmopenpage=Open the web page for the uploaded track?
- dialog.gpsies.activities=Activity types
- dialog.gpsies.activity.trekking=Hiking
- dialog.gpsies.activity.walking=Walking
- dialog.gpsies.activity.jogging=Running
- dialog.gpsies.activity.biking=Cycling
- dialog.gpsies.activity.motorbiking=Motorbiking
- dialog.gpsies.activity.snowshoe=Snowshoeing
- dialog.gpsies.activity.sailing=Sailing
- dialog.gpsies.activity.skating=Skating
dialog.mapillary.nonefound=No photos found
dialog.wikipedia.column.name=Article name
dialog.wikipedia.column.distance=Distance
dialog.pastecoordinates.desc=Enter or paste the coordinates here
dialog.pastecoordinates.coords=Coordinates
dialog.pastecoordinates.nothingfound=Please check the coordinates and try again
+ dialog.pastecoordinatelist.desc=Enter the coordinates for the new points with one point per line
+ dialog.pluscode.desc=Enter or paste the pluscode here
+ dialog.pluscode.code=Pluscode
+ dialog.pluscode.nothingfound=Please check the code and try again
dialog.help.help=Please see\n https://gpsprune.activityworkshop.net/\nfor more information and tips,\nincluding a PDF user guide you can buy.
dialog.about.version=Version
dialog.about.build=Build
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.keys.normalmodifier=Ctrl
dialog.keys.macmodifier=Command
- 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
- dialog.saveconfig.prune.languagecode=Language code (EN)
- dialog.saveconfig.prune.languagefile=Language file
- dialog.saveconfig.prune.gpsdevice=GPS device
- dialog.saveconfig.prune.gpsformat=GPS format
- dialog.saveconfig.prune.povrayfont=Povray font
- dialog.saveconfig.prune.gnuplotpath=Path to gnuplot
- dialog.saveconfig.prune.gpsbabelpath=Path to gpsbabel
- dialog.saveconfig.prune.exiftoolpath=Path to exiftool
- 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 size
- dialog.saveconfig.prune.colourscheme=Colour scheme
- dialog.saveconfig.prune.linewidth=Line width
- dialog.saveconfig.prune.kmltrackcolour=KML track colour
- dialog.saveconfig.prune.autosavesettings=Autosave settings
+ dialog.paths.prune.gnuplotpath=Path to gnuplot
+ dialog.paths.prune.gpsbabelpath=Path to gpsbabel
+ dialog.paths.prune.exiftoolpath=Path to exiftool
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.displaysettings.size.small=Small
dialog.displaysettings.size.medium=Medium
dialog.displaysettings.size.large=Large
+ dialog.displaysettings.windowstyle=Window style (requires restart)
+ dialog.displaysettings.windowstyle.default=Default
+ dialog.displaysettings.windowstyle.nimbus=Nimbus
dialog.downloadosm.desc=Confirm to download the raw OSM data for the specified area:
+dialog.earthdataauth.intro=<p>Configure username and password to access your NASA Earthdata login account.</p><p> Create an account at <tt>https://urs.earthdata.nasa.gov/users/new</tt>.</p>
+dialog.earthdataauth.user=Username
+dialog.earthdataauth.password=Password
+dialog.earthdataauth.authaccepted=Username and password accepted
+dialog.earthdataauth.authrejected=Username and password rejected
dialog.searchwikipedianames.search=Search for:
dialog.weather.location=Location
dialog.weather.update=Forecast updated
dialog.autoplay.rewind=Back to beginning
dialog.autoplay.pause=Pause
dialog.autoplay.play=Play
+ dialog.markers.halves=Halfway points
+ dialog.markers.half.distance=Half distance
+ dialog.markers.half.climb=Half climb
+ dialog.markers.half.descent=Half descent
+ dialog.projectpoint.desc=Enter the direction and distance to project this point
+ dialog.projectpoint.bearing=Bearing (degrees from N)
# 3d window
dialog.3d.title=GpsPrune Three-d view
confirm.reverserange=Range reversed
confirm.addtimeoffset=Time offset added
confirm.addaltitudeoffset=Altitude offset added
+confirm.removealtitudes=Altitudes removed
confirm.rearrangewaypoints=Waypoints rearranged
confirm.rearrangephotos=Photos rearranged
confirm.splitsegments=%d segment splits were made
confirm.sewsegments=%d segment joins were made
confirm.cutandmove=Selection moved
- confirm.interpolate=Points added
+ confirm.pointsadded=%d points added
confirm.convertnamestotimes=Waypoint names converted
confirm.saveexif.ok=Saved %d photo files
confirm.undo.single=operation undone
button.selectnone=Select none
button.preview=Preview
button.load=Load
- button.upload=Upload
button.guessfields=Guess fields
button.showwebpage=Show webpage
button.check=Check
details.lists.waypoints=Waypoints
details.lists.photos=Photos
details.lists.audio=Audio
+details.lists.segments=Segments
+details.lists.segments.label=Segment #
+details.lists.segments.to=to
details.photodetails=Photo details
details.nophoto=No photo selected
details.photo.loading=Loading
# Field names
fieldname.latitude=Latitude
fieldname.longitude=Longitude
+ fieldname.coordinates=Coordinates
fieldname.altitude=Altitude
fieldname.timestamp=Time
fieldname.time=Time
fieldname.speed=Speed
fieldname.verticalspeed=Vertical speed
fieldname.description=Description
+ fieldname.comment=Comment
fieldname.mediafilename=Filename
# Measurement units
undo.sewsegments=sew track segments
undo.addtimeoffset=add time offset
undo.addaltitudeoffset=add altitude offset
+undo.removealtitudes=remove altitudes
undo.rearrangewaypoints=rearrange waypoints
undo.cutandmove=move section
undo.connect=connect
error.load.unknownxml=Unrecognised xml format:
error.load.noxmlinzip=No xml file found inside zip file
error.load.othererror=Error reading file:
+ error.load.nopointsintext=No coordinate information found
error.jpegload.dialogtitle=Error loading photos
error.jpegload.nofilesfound=No files found
error.jpegload.nojpegsfound=No jpeg files found