X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Ffunction%2Fsrtm%2FLookupSrtmFunction.java;fp=tim%2Fprune%2Ffunction%2Fsrtm%2FLookupSrtmFunction.java;h=30183d2d6cd13c0e780a018bc4ca6dd1ba2444b5;hb=c0387c124840c9407e040600fda88f3c3e8f6aa6;hp=0000000000000000000000000000000000000000;hpb=1ee49ae3c8ef3aa2e63eadd458531e5f8bd4f92c;p=GpsPrune.git diff --git a/tim/prune/function/srtm/LookupSrtmFunction.java b/tim/prune/function/srtm/LookupSrtmFunction.java new file mode 100644 index 0000000..30183d2 --- /dev/null +++ b/tim/prune/function/srtm/LookupSrtmFunction.java @@ -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 tileList = new ArrayList(); + for (int i=0; i 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