X-Git-Url: http://gitweb.fperrin.net/?a=blobdiff_plain;f=tim%2Fprune%2Fcorrelate%2FPhotoCorrelator.java;h=f5f86b1ab36982565a44d9cac29d9bd7aff7ee46;hb=f35b6d628f68e3b5ef19965ad8988d0dd1eb8efa;hp=22237725c8daef673d99a7446f137054b65e559b;hpb=da0b1f449260a0b4a94318006382a9039726ef3e;p=GpsPrune.git diff --git a/tim/prune/correlate/PhotoCorrelator.java b/tim/prune/correlate/PhotoCorrelator.java index 2223772..f5f86b1 100644 --- a/tim/prune/correlate/PhotoCorrelator.java +++ b/tim/prune/correlate/PhotoCorrelator.java @@ -1,448 +1,90 @@ package tim.prune.correlate; -import java.awt.BorderLayout; -import java.awt.CardLayout; -import java.awt.Component; -import java.awt.Dimension; -import java.awt.FlowLayout; -import java.awt.event.ActionEvent; -import java.awt.event.ActionListener; -import java.util.Calendar; -import java.util.Iterator; -import java.util.TreeSet; - -import javax.swing.BorderFactory; -import javax.swing.BoxLayout; -import javax.swing.ButtonGroup; -import javax.swing.JButton; -import javax.swing.JComboBox; -import javax.swing.JDialog; -import javax.swing.JFrame; -import javax.swing.JLabel; import javax.swing.JOptionPane; -import javax.swing.JPanel; -import javax.swing.JRadioButton; -import javax.swing.JScrollPane; import javax.swing.JTable; -import javax.swing.JTextField; import tim.prune.App; +import tim.prune.DataSubscriber; import tim.prune.I18nManager; +import tim.prune.UpdateMessageBroker; import tim.prune.data.DataPoint; -import tim.prune.data.Distance; -import tim.prune.data.Field; +import tim.prune.data.MediaList; import tim.prune.data.Photo; import tim.prune.data.PhotoList; import tim.prune.data.TimeDifference; -import tim.prune.data.Timestamp; -import tim.prune.data.Track; -import tim.prune.data.TrackInfo; +import tim.prune.undo.UndoCorrelatePhotos; /** * Class to manage the automatic correlation of photos to points * including the GUI stuff to control the correlation options */ -public class PhotoCorrelator +public class PhotoCorrelator extends Correlator { - private App _app; - private JFrame _parentFrame; - private JDialog _dialog; - private JButton _nextButton = null, _backButton = null; - private JButton _okButton = null; - private JPanel _cards = null; - private JTable _photoSelectionTable = null; - private JLabel _tipLabel = null; - private JTextField _offsetHourBox = null, _offsetMinBox = null, _offsetSecBox = null; - private JRadioButton _photoLaterOption = null, _pointLaterOption = null; - private JRadioButton _timeLimitRadio = null, _distLimitRadio = null; - private JTextField _limitMinBox = null, _limitSecBox = null; - private JTextField _limitDistBox = null; - private JComboBox _distUnitsDropdown = null; - private JTable _previewTable = null; - private boolean _firstTabAvailable = false; - private boolean _previewEnabled = false; // flag required to enable preview function on second panel - - /** * Constructor * @param inApp App object to report actions to - * @param inFrame parent frame for dialogs - */ - public PhotoCorrelator(App inApp, JFrame inFrame) - { - _app = inApp; - _parentFrame = inFrame; - _dialog = new JDialog(inFrame, I18nManager.getText("dialog.correlate.title"), true); - _dialog.setLocationRelativeTo(inFrame); - _dialog.getContentPane().add(makeDialogContents()); - _dialog.pack(); - } - - - /** - * Reset dialog and show it - */ - public void begin() - { - // Check whether track has timestamps, exit if not - if (!_app.getTrackInfo().getTrack().hasData(Field.TIMESTAMP)) - { - JOptionPane.showMessageDialog(_parentFrame, I18nManager.getText("dialog.correlate.notimestamps"), - I18nManager.getText("dialog.correlate.title"), JOptionPane.INFORMATION_MESSAGE); - return; - } - // Check for any non-correlated photos, show warning continue/cancel - if (!trackHasUncorrelatedPhotos()) - { - Object[] buttonTexts = {I18nManager.getText("button.continue"), I18nManager.getText("button.cancel")}; - if (JOptionPane.showOptionDialog(_parentFrame, I18nManager.getText("dialog.correlate.nouncorrelatedphotos"), - I18nManager.getText("dialog.correlate.title"), JOptionPane.YES_NO_OPTION, - JOptionPane.WARNING_MESSAGE, null, buttonTexts, buttonTexts[1]) - == JOptionPane.NO_OPTION) - { - return; - } - } - PhotoSelectionTableModel model = makePhotoSelectionTableModel(_app.getTrackInfo()); - _firstTabAvailable = model != null && model.getRowCount() > 0; - CardLayout cl = (CardLayout) _cards.getLayout(); - if (_firstTabAvailable) - { - cl.first(_cards); - _nextButton.setEnabled(true); - _backButton.setEnabled(false); - _tipLabel.setVisible(false); - _photoSelectionTable.setModel(model); - _previewEnabled = false; - for (int i=0; i 0.0 && correlatePhoto) { + if (angDistLimit > 0.0 && correlatePhoto) + { final double angDistPair = DataPoint.calculateRadiansBetween(pair.getPointBefore(), pair.getPointAfter()); - //System.out.println("(dist between pair is " + angDistPair + ") which means " - // + Distance.convertRadiansToDistance(angDistPair, Distance.UNITS_METRES) + "m"); double frac = pair.getFraction(); if (frac > 0.5) {frac = 1 - frac;} final double angDistPhoto = angDistPair * frac; correlatePhoto = (angDistPhoto < angDistLimit); } // Don't select photos which are already correlated to the same point - if (pair.getSecondsBefore() == 0L && pair.getPointBefore().getPhoto() != null - && pair.getPointBefore().getPhoto().equals(photo)) { + if (pair.getSecondsBefore() == 0L && pair.getPointBefore().isDuplicate(photo.getDataPoint())) { correlatePhoto = false; } row.setCorrelateFlag(correlatePhoto); - model.addPhotoRow(row); + model.addRow(row); } _previewTable.setModel(model); // Set distance units @@ -454,208 +96,110 @@ public class PhotoCorrelator _previewTable.getColumnModel().getColumn(i).setPreferredWidth(colWidths[i]); } // check if any photos found - _okButton.setEnabled(model.hasPhotosSelected()); - if (inShowWarning && !model.hasPhotosSelected()) + _okButton.setEnabled(model.hasAnySelected()); + if (inShowWarning && !model.hasAnySelected()) { JOptionPane.showMessageDialog(_dialog, I18nManager.getText("dialog.correlate.alloutsiderange"), - I18nManager.getText("dialog.correlate.title"), JOptionPane.ERROR_MESSAGE); + I18nManager.getText(getNameKey()), JOptionPane.ERROR_MESSAGE); } } - /** - * Parse the time limit values entered and validate them - * @return TimeDifference object describing limit - */ - private TimeDifference parseTimeLimit() - { - if (!_timeLimitRadio.isSelected()) {return null;} - int mins = getValue(_limitMinBox.getText()); - _limitMinBox.setText("" + mins); - int secs = getValue(_limitSecBox.getText()); - _limitSecBox.setText("" + secs); - if (mins <= 0 && secs <= 0) {return null;} - return new TimeDifference(0, mins, secs, true); - } /** - * Parse the distance limit value entered and validate - * @return angular distance in radians + * Finish the correlation by modifying the track + * and passing the Undo information back to the App */ - private double parseDistanceLimit() + protected void finishCorrelation() { - double value = -1.0; - if (_distLimitRadio.isSelected()) - { - try - { - value = Double.parseDouble(_limitDistBox.getText()); - } - catch (NumberFormatException nfe) {} - } - if (value <= 0.0) { - _limitDistBox.setText("0"); - return -1.0; - } - _limitDistBox.setText("" + value); - return Distance.convertDistanceToRadians(value, getSelectedDistanceUnits()); - } + PointMediaPair[] pointPairs = getPointPairs(); + if (pointPairs == null || pointPairs.length <= 0) {return;} - - /** - * @return the selected distance units from the dropdown - */ - private int getSelectedDistanceUnits() - { - final int[] distUnits = {Distance.UNITS_KILOMETRES, Distance.UNITS_METRES, Distance.UNITS_MILES}; - return distUnits[_distUnitsDropdown.getSelectedIndex()]; - } - - - /** - * Try to parse the given string - * @param inText String to parse - * @return value if parseable, 0 otherwise - */ - private static int getValue(String inText) - { - int value = 0; - try { - value = Integer.parseInt(inText); - } - catch (NumberFormatException nfe) {} - return value; - } - - - /** - * Get the point pair surrounding the given photo - * @param inTrack track object - * @param inPhoto photo object - * @param inOffset time offset to apply to photos - * @return point pair resulting from correlation - */ - private static PointPair getPointPairForPhoto(Track inTrack, Photo inPhoto, TimeDifference inOffset) - { - PointPair pair = new PointPair(inPhoto); - // Add offet to photo timestamp - Timestamp photoStamp = inPhoto.getTimestamp().subtractOffset(inOffset); - int numPoints = inTrack.getNumPoints(); - for (int i=0; i 0) { - PhotoPreviewTableRow row = model.getRow(i); - // add all selected pairs to array (other elements remain null) - if (row.getCorrelateFlag().booleanValue()) + // make new array for added points + DataPoint[] addedPoints = new DataPoint[numPointsToCreate]; + int pointNum = 0; + DataPoint pointToAdd = null; + for (i=0; i 0L) + { + // interpolate point + pointToAdd = DataPoint.interpolate(pair.getPointBefore(), pair.getPointAfter(), pair.getFraction()); + } + if (pointToAdd != null) + { + // link photo to point + pointToAdd.setPhoto((Photo) pair.getMedia()); + pair.getMedia().setDataPoint(pointToAdd); + // set to start of segment so not joined in track + pointToAdd.setSegmentStart(true); + // add to point array + addedPoints[pointNum] = pointToAdd; + pointNum++; + } + } } + // expand track + _app.getTrackInfo().getTrack().appendPoints(addedPoints); } - return pairs; - } - - /** - * @return time difference of local time zone from UTC when the first photo was taken - */ - private TimeDifference getTimezoneOffset() - { - Calendar cal = null; - // Base time difference on DST when first photo was taken - Photo firstPhoto = _app.getTrackInfo().getPhotoList().getPhoto(0); - if (firstPhoto != null && firstPhoto.getTimestamp() != null) { - cal = firstPhoto.getTimestamp().getCalendar(); - } - else { - // No photo or no timestamp, just use current time - cal = Calendar.getInstance(); - } - // Both time zone offset and dst offset are based on milliseconds, so convert to seconds - TimeDifference timeDiff = new TimeDifference((cal.get(Calendar.ZONE_OFFSET) + cal.get(Calendar.DST_OFFSET)) / 1000); - return timeDiff; - } - - - /** - * Calculate the median index to select from the table - * @param inModel table model - * @return index of entry to select from table - */ - private static int getMedianIndex(PhotoSelectionTableModel inModel) - { - // make sortable list - TreeSet set = new TreeSet(); - // loop through rows of table adding to list - int numRows = inModel.getRowCount(); - int i; - for (i=0; i