Ticket #24347: ticket_24347.patch

File ticket_24347.patch, 21.2 KB (added by StephaneP, 10 months ago)
  • src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java

    diff --git a/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java b/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java
    index d5a1d71fa6..b8de9a5bbd 100644
    a b public final class GpxImageCorrelation {  
    7676        final GpxImageDirectionPositionSettings dirpos = settings.getDirectionPositionSettings();
    7777        final GpxImageDatumSettings datumSettings = settings.getDatumSettings();
    7878        final long offset = settings.getOffset();
     79        final TimeSource imgTimeSource = settings.getImgTimeSource();
    7980
    8081        boolean isFirst = true;
    8182        long prevWpTime = 0;
    public final class GpxImageCorrelation {  
    144145                        }
    145146                    }
    146147                    WayPoint nextWp = i < size - 1 ? wps.get(i + 1) : null;
    147                     ret += matchPoints(images, prevWp, prevWpTime, curWp, curWpTime, offset,
     148                    ret += matchPoints(images, prevWp, prevWpTime, curWp, curWpTime, imgTimeSource, offset,
    148149                                       interpolate, tagTime, nextWp, dirpos, datumSettings);
    149150                    prevWp = curWp;
    150151                    prevWpTime = curWpTime;
    public final class GpxImageCorrelation {  
    152153            }
    153154        }
    154155        if (trkTag && prevWp != null) {
    155             ret += matchPoints(images, prevWp, prevWpTime, prevWp, prevWpTime, offset,
     156            ret += matchPoints(images, prevWp, prevWpTime, prevWp, prevWpTime, imgTimeSource, offset,
    156157                               false, trkTagTime, null, dirpos, datumSettings);
    157158        }
    158159        Logging.debug("Correlated {0} total points", ret);
    public final class GpxImageCorrelation {  
    361362                                        long prevWpTime,
    362363                                        WayPoint curWp,
    363364                                        long curWpTime,
     365                                        TimeSource imgTimeSource,
    364366                                        long offset,
    365367                                        boolean interpolate,
    366368                                        int tagTime,
    public final class GpxImageCorrelation {  
    375377        if (isLast) {
    376378            i = images.size() - 1;
    377379        } else {
    378             i = getLastIndexOfListBefore(images, curWpTime);
     380            i = getLastIndexOfListBefore(images, curWpTime, imgTimeSource);
    379381        }
    380382
    381383        if (Logging.isDebugEnabled()) {
    public final class GpxImageCorrelation {  
    426428            while (i >= 0) {
    427429                final GpxImageEntry curImg = images.get(i);
    428430                final GpxImageEntry curTmp = curImg.getTmp();
    429                 final long time = curImg.getExifInstant().toEpochMilli();
     431                final long time = curImg.getThisInstant(imgTimeSource).toEpochMilli();
    430432                if ((!isLast && time > curWpTime) || time < prevWpTime) {
    431433                    break;
    432434                }
    public final class GpxImageCorrelation {  
    459461            LatLon nextCoorForDirection = nextWp.getCoor();
    460462            while (i >= 0) {
    461463                final GpxImageEntry curImg = images.get(i);
    462                 final long imgTime = curImg.getExifInstant().toEpochMilli();
     464                final long imgTime = curImg.getThisInstant(imgTimeSource).toEpochMilli();
    463465                if (imgTime < prevWpTime) {
    464466                    break;
    465467                }
    public final class GpxImageCorrelation {  
    547549                            curTmp.setExifGpsDatum("WGS-84");
    548550                    }
    549551
    550                     curTmp.setGpsTime(curImg.getExifInstant().minusMillis(offset));
     552                    curTmp.setGpsTime(curImg.getThisInstant(imgTimeSource).minusMillis(offset));
    551553                    curTmp.flagNewGpsData();
    552554                    curImg.tmpUpdated();
    553555
    public final class GpxImageCorrelation {  
    578580     * @param searchedTime time to search
    579581     * @return index of last image before given time
    580582     */
    581     private static int getLastIndexOfListBefore(List<? extends GpxImageEntry> images, long searchedTime) {
     583    private static int getLastIndexOfListBefore(List<? extends GpxImageEntry> images, long searchedTime, TimeSource imgTimeSource) {
    582584        int lstSize = images.size();
    583585
    584586        // No photos or the first photo taken is later than the search period
    585         if (lstSize == 0 || searchedTime < images.get(0).getExifInstant().toEpochMilli())
     587        if (lstSize == 0 || searchedTime < images.get(0).getThisInstant(imgTimeSource).toEpochMilli())
    586588            return -1;
    587589
    588590        // The search period is later than the last photo
    589         if (searchedTime > images.get(lstSize - 1).getExifInstant().toEpochMilli())
     591        if (searchedTime > images.get(lstSize - 1).getThisInstant(imgTimeSource).toEpochMilli())
    590592            return lstSize-1;
    591593
    592594        // The searched index is somewhere in the middle, do a binary search from the beginning
    public final class GpxImageCorrelation {  
    595597        int endIndex = lstSize-1;
    596598        while (endIndex - startIndex > 1) {
    597599            curIndex = (endIndex + startIndex) / 2;
    598             if (searchedTime > images.get(curIndex).getExifInstant().toEpochMilli()) {
     600            if (searchedTime > images.get(curIndex).getThisInstant(imgTimeSource).toEpochMilli()) {
    599601                startIndex = curIndex;
    600602            } else {
    601603                endIndex = curIndex;
    602604            }
    603605        }
    604         if (searchedTime < images.get(endIndex).getExifInstant().toEpochMilli())
     606        if (searchedTime < images.get(endIndex).getThisInstant(imgTimeSource).toEpochMilli())
    605607            return startIndex;
    606608
    607609        // This final loop is to check if photos with the exact same EXIF time follows
    608         while ((endIndex < (lstSize - 1)) && (images.get(endIndex).getExifInstant().toEpochMilli()
    609                 == images.get(endIndex + 1).getExifInstant().toEpochMilli())) {
     610        while ((endIndex < (lstSize - 1)) && (images.get(endIndex).getThisInstant(imgTimeSource).toEpochMilli()
     611                == images.get(endIndex + 1).getThisInstant(imgTimeSource).toEpochMilli())) {
    610612            endIndex++;
    611613        }
    612614        return endIndex;
  • src/org/openstreetmap/josm/data/gpx/GpxImageCorrelationSettings.java

    diff --git a/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelationSettings.java b/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelationSettings.java
    index 5e2d9ef699..292ba46805 100644
    a b public class GpxImageCorrelationSettings {  
    1111
    1212    private final long offset;
    1313    private final boolean forceTags;
     14    private final TimeSource imgTimeSource;
    1415    private final GpxImageDirectionPositionSettings directionPositionSettings;
    1516    private final GpxImageDatumSettings datumSettings;
    1617
    public class GpxImageCorrelationSettings {  
    2021     * @param forceTags force tagging of all photos, otherwise prefs are used
    2122     */
    2223    public GpxImageCorrelationSettings(long offset, boolean forceTags) {
    23         this(offset, forceTags,
     24        this(offset, forceTags, TimeSource.EXIFCAMTIME,
    2425        new GpxImageDirectionPositionSettings(false, 0, false, 0, 0, 0),
    2526        new GpxImageDatumSettings(false, null)
    2627        );
    public class GpxImageCorrelationSettings {  
    3031     * Constructs a new {@code GpxImageCorrelationSettings}.
    3132     * @param offset offset in milliseconds
    3233     * @param forceTags force tagging of all photos, otherwise prefs are used
     34     * @param imgTimeSource select image clock source:
     35     *                      "exifCamTime" for camera internal clock
     36     *                      "exifGpsTime for the GPS clock of the camera
    3337     * @param directionPositionSettings direction/position settings
     38     * @since xxx @imgTimeSource was added
    3439     */
    35     public GpxImageCorrelationSettings(long offset, boolean forceTags,
     40    public GpxImageCorrelationSettings(long offset, boolean forceTags, TimeSource imgTimeSource,
    3641            GpxImageDirectionPositionSettings directionPositionSettings) {
    37         this(offset, forceTags, directionPositionSettings,
     42        this(offset, forceTags, imgTimeSource, directionPositionSettings,
    3843        new GpxImageDatumSettings(false, null));
    3944    }
    4045
    public class GpxImageCorrelationSettings {  
    4247     * Constructs a new {@code GpxImageCorrelationSettings}.
    4348     * @param offset offset in milliseconds
    4449     * @param forceTags force tagging of all photos, otherwise prefs are used
     50     * @param imgTimeSource select image clock source:
     51     *                      "exifCamTime" for camera internal clock
     52     *                      "exifGpsTime for the GPS clock of the camera
    4553     * @param directionPositionSettings direction/position settings
    4654     * @param datumSettings GPS datum settings
    4755     * @since 19387 @datumSettings was added
     56     * @since xxx @imgTimeSource was added
    4857     */
    49     public GpxImageCorrelationSettings(long offset, boolean forceTags,
     58    public GpxImageCorrelationSettings(long offset, boolean forceTags, TimeSource imgTimeSource,
    5059            GpxImageDirectionPositionSettings directionPositionSettings,
    5160            GpxImageDatumSettings datumSettings) {
    5261        this.offset = offset;
    5362        this.forceTags = forceTags;
     63        this.imgTimeSource = imgTimeSource;
    5464        this.directionPositionSettings = Objects.requireNonNull(directionPositionSettings);
    5565        this.datumSettings = Objects.requireNonNull(datumSettings);
    5666    }
    public class GpxImageCorrelationSettings {  
    7181        return forceTags;
    7282    }
    7383
     84    /**
     85     * Return the selected image clock source, which is camera internal time, or GPS time
     86     * @return the clock source
     87     * @since xxx
     88     */
     89    public TimeSource getImgTimeSource() {
     90        return imgTimeSource;
     91    }
     92
    7493    /**
    7594     * Returns the direction/position settings.
    7695     * @return the direction/position settings
    public class GpxImageCorrelationSettings {  
    91110    @Override
    92111    public String toString() {
    93112        return "[offset=" + offset + ", forceTags=" + forceTags
     113                + ", clock source=" + imgTimeSource
    94114                + ", directionPositionSettings=" + directionPositionSettings
    95115                + ", datumSettings=" + datumSettings + ']';
    96116    }
  • src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java

    diff --git a/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java b/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java
    index 9842da34c8..9f2072b15d 100644
    a b public class GpxImageEntry implements Comparable<GpxImageEntry>, IQuadBucketType  
    336336        return exifGpsTime != null;
    337337    }
    338338
     339    /**
     340     * Return the time value selected with the parameter.
     341     * @param timeSource the wanted time value, exifCamTime or exifGpsTime
     342     * @return exifInstant or exifGpsInstant value
     343     * @since xxx
     344     */
     345    @Override
     346    public Instant getThisInstant(TimeSource timeSource) {
     347        switch (timeSource) {
     348            case EXIFGPSTIME:
     349                return getExifGpsInstant();
     350            case EXIFCAMTIME:
     351                return getExifInstant();
     352        }
     353        return null;
     354    }
     355
    339356    private static Date getDefensiveDate(Instant date) {
    340357        if (date == null)
    341358            return null;
  • src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java b/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java
    index 14d7b3f843..43bfaac1aa 100644
    a b import java.util.function.Consumer;  
    3232
    3333import javax.swing.AbstractAction;
    3434import javax.swing.BorderFactory;
     35import javax.swing.ButtonGroup;
    3536import javax.swing.DefaultComboBoxModel;
    3637import javax.swing.JButton;
    3738import javax.swing.JCheckBox;
    3839import javax.swing.JLabel;
    3940import javax.swing.JOptionPane;
    4041import javax.swing.JPanel;
     42import javax.swing.JRadioButton;
    4143import javax.swing.JSeparator;
    4244import javax.swing.SwingConstants;
    4345import javax.swing.event.ChangeEvent;
    import org.openstreetmap.josm.data.gpx.GpxImageCorrelationSettings;  
    5658import org.openstreetmap.josm.data.gpx.GpxImageDatumSettings;
    5759import org.openstreetmap.josm.data.gpx.GpxTimeOffset;
    5860import org.openstreetmap.josm.data.gpx.GpxTimezone;
     61import org.openstreetmap.josm.data.gpx.TimeSource;
    5962import org.openstreetmap.josm.data.gpx.WayPoint;
    6063import org.openstreetmap.josm.data.osm.visitor.BoundingXYVisitor;
    6164import org.openstreetmap.josm.gui.ExtendedDialog;
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    8891
    8992    private static JosmComboBoxModel<GpxDataWrapper> gpxModel;
    9093    private static boolean forceTags;
     94    private static TimeSource imgTimeSource;
    9195
    9296    private final transient GeoImageLayer yLayer;
    9397    private transient CorrelationSupportLayer supportLayer;
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    253257    private JButton buttonSupport;
    254258    private JosmTextField tfTimezone;
    255259    private JosmTextField tfOffset;
     260    private JRadioButton rbTimeFromCamera;
     261    private JRadioButton rbTimeFromGps;
    256262    private JCheckBox cbExifImg;
    257263    private JCheckBox cbTaggedImg;
    258264    private JCheckBox cbShowThumbs;
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    520526        tfOffset = new JosmTextField(10);
    521527        tfOffset.setText(delta.formatOffset());
    522528
     529        // Image Time/Clock source choice
     530        rbTimeFromCamera = new JRadioButton(tr("Camera clock"));
     531        rbTimeFromCamera.setSelected(true);
     532        rbTimeFromGps = new JRadioButton(tr("Camera GPS clock"));       
     533        ButtonGroup timeSourceGroup = new ButtonGroup();
     534        timeSourceGroup.add(rbTimeFromCamera);
     535        timeSourceGroup.add(rbTimeFromGps);
     536
    523537        JButton buttonViewGpsPhoto = new JButton(tr("<html>Use photo of an accurate clock,<br>e.g. GPS receiver display</html>"));
    524538        buttonViewGpsPhoto.setIcon(ImageProvider.get("clock"));
    525539        buttonViewGpsPhoto.addActionListener(new SetOffsetActionListener());
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    586600        gbc.gridx = 3;
    587601        panelTf.add(buttonAdjust, gbc);
    588602
     603        // Image time source choice
     604        gbc = GBC.eol();
     605        gbc.gridx = 0;
     606        gbc.gridy = y++;
     607        panelTf.add(new JLabel(tr("Image time source:")), gbc);
     608
     609        gbc = GBC.eol();
     610        gbc.gridx = 1;
     611        gbc.gridy = y++;
     612        panelTf.add(rbTimeFromCamera, gbc);
     613
     614        gbc = GBC.eol();
     615        gbc.gridx = 1;
     616        gbc.gridy = y++;
     617        panelTf.add(rbTimeFromGps, gbc);
     618
    589619        gbc = GBC.eol().grid(0, y++).fill(GridBagConstraints.HORIZONTAL).insets(0, 12, 0, 0);
    590620        panelTf.add(new JSeparator(SwingConstants.HORIZONTAL), gbc);
    591621        panelTf.add(labelPosition, GBC.eol().grid(0, y++));
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    619649        //TODO An AutoCompComboBox would be nice to list the recent datum values. I don't have the skill to add it.
    620650        tfDatum = new JosmTextField(loadGpsDatum(), 8);
    621651        tfDatum.setToolTipText(tr("<html>Enter the datum for your images coordinates. Default value is WGS-84.<br>" +
    622                                 "For RTK it could be your local CRS epsg code.<br>(e.g. EPSG:9782 for France mainland.)</html>"));
     652                                "For RTK it could be your local CRS epsg code.<br>(e.g. EPSG:9781 for France mainland.)</html>"));
    623653        tfDatum.setEnabled(false);
    624654
    625655        expertPanel.add(labelExtTags, GBC.eol().grid(0, 1));
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    651681
    652682        tfTimezone.getDocument().addDocumentListener(statusBarUpdater);
    653683        tfOffset.getDocument().addDocumentListener(statusBarUpdater);
     684        rbTimeFromCamera.addItemListener(statusBarUpdaterWithRepaint);
     685        rbTimeFromGps.addItemListener(statusBarUpdaterWithRepaint);
    654686        cbExifImg.addItemListener(statusBarUpdaterWithRepaint);
    655687        cbTaggedImg.addItemListener(statusBarUpdaterWithRepaint);
    656688        cbAddGpsDatum.addItemListener(statusBarUpdaterWithRepaint);
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    783815                return e.getMessage();
    784816            }
    785817
     818            // Set image time source from the radio button status
     819            if (rbTimeFromGps.isSelected()) {
     820                imgTimeSource = TimeSource.EXIFGPSTIME;
     821            } else {
     822                imgTimeSource = TimeSource.EXIFCAMTIME;
     823            }
     824
    786825            // The selection of images we are about to correlate may have changed.
    787826            // So reset all images.
    788827            yLayer.discardTmp();
    public class CorrelateGpxWithImages extends AbstractAction implements ExpertMode  
    799838            final long offsetMs = ((long) (timezone.getHours() * TimeUnit.HOURS.toMillis(1))) + delta.getMilliseconds(); // in milliseconds
    800839            lastNumMatched = GpxImageCorrelation.matchGpxTrack(dateImgLst, selGpx.data,
    801840                    pDirectionPosition.isVisible() ?
    802                             new GpxImageCorrelationSettings(offsetMs, forceTags, pDirectionPosition.getSettings(),
     841                            new GpxImageCorrelationSettings(offsetMs, forceTags, imgTimeSource, pDirectionPosition.getSettings(),
    803842                                                            new GpxImageDatumSettings(cbAddGpsDatum.isSelected(), tfDatum.getText())) :
    804843                            new GpxImageCorrelationSettings(offsetMs, forceTags));
    805844
  • src/org/openstreetmap/josm/gui/layer/geoimage/EditImagesSequenceAction.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/EditImagesSequenceAction.java b/src/org/openstreetmap/josm/gui/layer/geoimage/EditImagesSequenceAction.java
    index ee93220b87..6d84ef2310 100644
    a b import javax.swing.event.ChangeListener;  
    1616import org.openstreetmap.josm.actions.JosmAction;
    1717import org.openstreetmap.josm.data.gpx.GpxImageCorrelation;
    1818import org.openstreetmap.josm.data.gpx.GpxImageCorrelationSettings;
     19import org.openstreetmap.josm.data.gpx.TimeSource;
    1920import org.openstreetmap.josm.gui.ExtendedDialog;
    2021import org.openstreetmap.josm.gui.MainApplication;
    2122import org.openstreetmap.josm.gui.layer.geoimage.CorrelateGpxWithImages.RepaintTheMapListener;
    public class EditImagesSequenceAction extends JosmAction {  
    8283            // Create a temporary copy for each image
    8384            dateImgLst.forEach(ie -> ie.createTmp().unflagNewGpsData());
    8485            GpxImageCorrelation.matchGpxTrack(dateImgLst, yLayer.getFauxGpxData(),
    85                             new GpxImageCorrelationSettings(0, false, pDirectionPosition.getSettings()));
     86                            new GpxImageCorrelationSettings(0, false, TimeSource.EXIFCAMTIME, pDirectionPosition.getSettings()));
    8687            yLayer.updateBufferAndRepaint();
    8788        }
    8889    }
  • src/org/openstreetmap/josm/gui/layer/geoimage/ImageMetadata.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/ImageMetadata.java b/src/org/openstreetmap/josm/gui/layer/geoimage/ImageMetadata.java
    index 7aebccd962..1c01723c6c 100644
    a b import java.time.Instant;  
    1111import java.util.List;
    1212
    1313import org.openstreetmap.josm.data.coor.ILatLon;
     14import org.openstreetmap.josm.data.gpx.TimeSource;
    1415import org.openstreetmap.josm.data.imagery.street_level.Projections;
    1516
    1617/**
    public interface ImageMetadata {  
    115116     */
    116117    boolean hasExifGpsTime();
    117118
     119    /**
     120     * Return the time value selected with the parameter.
     121     * @param timeSource the wanted time value, exifCamTime or exifGpsTime
     122     * @return exifInstant or exifGpsInstant value
     123     * @since xxx
     124     */
     125    Instant getThisInstant(TimeSource timeSource);
     126
    118127    /**
    119128     * Get the EXIF coordinates
    120129     * @return The location of the image
  • src/org/openstreetmap/josm/gui/layer/geoimage/RemoteEntry.java

    diff --git a/src/org/openstreetmap/josm/gui/layer/geoimage/RemoteEntry.java b/src/org/openstreetmap/josm/gui/layer/geoimage/RemoteEntry.java
    index 344c8b5e11..a3ecf8ffc4 100644
    a b import java.util.Objects;  
    1717import java.util.function.Supplier;
    1818
    1919import org.openstreetmap.josm.data.coor.ILatLon;
     20import org.openstreetmap.josm.data.gpx.TimeSource;
    2021import org.openstreetmap.josm.data.imagery.street_level.IImageEntry;
    2122import org.openstreetmap.josm.data.imagery.street_level.Projections;
    2223import org.openstreetmap.josm.tools.HttpClient;
    public class RemoteEntry implements IImageEntry<RemoteEntry>, ImageMetadata {  
    360361        return this.exifTime != null;
    361362    }
    362363
     364    @Override
     365    public Instant getThisInstant(TimeSource timeSource) {
     366        return this.getThisInstant(timeSource);
     367    }
     368
    363369    @Override
    364370    public Instant getExifGpsInstant() {
    365371        return this.exifGpsTime;