Changeset 19387 in josm


Ignore:
Timestamp:
2025-04-23T18:34:33+02:00 (8 days ago)
Author:
stoecker
Message:

see #24238 - support more EXIF data in image correlation

Location:
trunk
Files:
2 added
21 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/ImageData.java

    r19112 r19387  
    367367
    368368    /**
     369     * Update the GPS track direction of the image and trigger update.
     370     * @param img the image to update
     371     * @param trackDirection the new GPS track direction
     372     * @since 19387
     373     */
     374    public void updateImageGpsTrack(ImageEntry img, double trackDirection) {
     375        img.setExifGpsTrack(trackDirection);
     376        afterImageUpdated(img);
     377    }
     378
     379    /**
     380     * Update the image horizontal positioning error and trigger update.
     381     * @param img the image to update
     382     * @param hposerr the new horizontal positionning error
     383     * @since 19387
     384     */
     385    public void updateImageHPosErr(ImageEntry img, double hposerr) {
     386        img.setExifHPosErr(hposerr);
     387        afterImageUpdated(img);
     388    }
     389
     390    /**
     391     * Update the image GPS differential mode and trigger update.
     392     * @param img the image to update
     393     * @param gpsDiffMode the new GPS differential mode
     394     * @since 19387
     395     */
     396    public void updateImageGpsDiffMode(ImageEntry img, Integer gpsDiffMode) {
     397        img.setGpsDiffMode(gpsDiffMode);
     398        afterImageUpdated(img);
     399    }
     400
     401    /**
     402     * Update the image GPS 2d/3d mode value and trigger update.
     403     * @param img the image to update
     404     * @param gps2d3dMode the new 2d/3d GPS mode
     405     * @since 19387
     406     */
     407    public void updateImageGps2d3dMode(ImageEntry img, Integer gps2d3dMode) {
     408        img.setGps2d3dMode(gps2d3dMode);
     409        afterImageUpdated(img);
     410    }
     411
     412    /**
     413     * Update the image GPS DOP value and trigger update.
     414     * @param img the image to update
     415     * @param exifGpsDop the new GPS DOP value
     416     * @since 19387
     417     */
     418    public void updateImageExifGpsDop(ImageEntry img, Double exifGpsDop) {
     419        img.setExifGpsDop(exifGpsDop);
     420        afterImageUpdated(img);
     421    }
     422
     423    /**
     424     * Update the image GPS datum and trigger update.
     425     * @param img the image to update
     426     * @param exifGpsDatum the new datum string value
     427     * @since 19387
     428     */
     429    public void updateImageExifGpsDatum(ImageEntry img, String exifGpsDatum) {
     430        img.setExifGpsDatum(exifGpsDatum);
     431        afterImageUpdated(img);
     432    }
     433
     434    /**
     435     * Update the image GPS processing method and trigger update.
     436     * @param img the image to update
     437     * @param exifGpsProcMethod the new GPS processing method
     438     * @since 19387
     439     */
     440    public void updateImageExifGpsProcMethod(ImageEntry img, String exifGpsProcMethod) {
     441        img.setExifGpsProcMethod(exifGpsProcMethod);
     442        afterImageUpdated(img);
     443    }
     444
     445    /**
    369446     * Manually trigger the {@link ImageDataUpdateListener#imageDataUpdated(ImageData)}
    370447     */
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxConstants.java

    r19316 r19387  
    146146    String PT_TIME = "time";
    147147
     148    /** True Course/Bearing angle over ground.
     149     * @since 19387
     150     */
     151    String PT_COURSE = "course";
     152
    148153    /** Magnetic variation (in degrees) at the point. 0.0 <= value < 360.0 */
    149154    String PT_MAGVAR = "magvar";
     
    189194     */
    190195    List<String> WPT_KEYS = Collections.unmodifiableList(Arrays.asList(PT_ELE, PT_TIME, PT_MAGVAR, PT_GEOIDHEIGHT,
    191             GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, PT_SYM, PT_TYPE,
    192             PT_FIX, PT_SAT, PT_HDOP, PT_VDOP, PT_PDOP, PT_AGEOFDGPSDATA, PT_DGPSID, PT_STD_HDEV, PT_STD_VDEV));
     196            GPX_NAME, GPX_CMT, GPX_DESC, GPX_SRC, META_LINKS, PT_SYM, PT_TYPE, PT_FIX, PT_SAT, PT_COURSE,
     197            PT_HDOP, PT_VDOP, PT_PDOP, PT_AGEOFDGPSDATA, PT_DGPSID, PT_STD_HDEV, PT_STD_VDEV));
    193198
    194199    /**
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelation.java

    r18494 r19387  
    22package org.openstreetmap.josm.data.gpx;
    33
     4import java.util.Arrays;
    45import java.util.ArrayList;
    56import java.util.Collection;
     
    7374
    7475        final GpxImageDirectionPositionSettings dirpos = settings.getDirectionPositionSettings();
     76        final GpxImageDatumSettings datumSettings = settings.getDatumSettings();
    7577        final long offset = settings.getOffset();
    7678
     
    142144                    }
    143145                    WayPoint nextWp = i < size - 1 ? wps.get(i + 1) : null;
    144                     ret += matchPoints(images, prevWp, prevWpTime, curWp, curWpTime, offset, interpolate, tagTime, nextWp, dirpos);
     146                    ret += matchPoints(images, prevWp, prevWpTime, curWp, curWpTime, offset,
     147                                       interpolate, tagTime, nextWp, dirpos, datumSettings);
    145148                    prevWp = curWp;
    146149                    prevWpTime = curWpTime;
     
    149152        }
    150153        if (trkTag && prevWp != null) {
    151             ret += matchPoints(images, prevWp, prevWpTime, prevWp, prevWpTime, offset, false, trkTagTime, null, dirpos);
     154            ret += matchPoints(images, prevWp, prevWpTime, prevWp, prevWpTime, offset,
     155                               false, trkTagTime, null, dirpos, datumSettings);
    152156        }
    153157        Logging.debug("Correlated {0} total points", ret);
     
    210214    }
    211215
    212     private static int matchPoints(List<? extends GpxImageEntry> images, WayPoint prevWp, long prevWpTime, WayPoint curWp, long curWpTime,
    213             long offset, boolean interpolate, int tagTime, WayPoint nextWp, GpxImageDirectionPositionSettings dirpos) {
     216    static Double getHPosErr(WayPoint wp) {
     217        if (wp != null) {
     218            if (wp.attr.get(GpxConstants.PT_STD_HDEV) instanceof Float) {
     219                Float hposerr = (Float) wp.attr.get(GpxConstants.PT_STD_HDEV);
     220                if (hposerr != null) {
     221                    return hposerr.doubleValue();
     222                }
     223            } else if (wp.attr.get(GpxConstants.PT_STD_HDEV) instanceof Double) {               
     224                Double hposerr = (Double) wp.attr.get(GpxConstants.PT_STD_HDEV);
     225                if (hposerr != null) {
     226                    return hposerr;
     227                }
     228            }
     229        }
     230        return null;
     231    }
     232
     233    static Double getGpsDop(WayPoint wp) {
     234        if (wp != null) {
     235            if (wp.attr.get(GpxConstants.PT_PDOP) != null) {
     236                if (wp.attr.get(GpxConstants.PT_PDOP) instanceof Float) {
     237                    Float pdopvalue = (Float) wp.attr.get(GpxConstants.PT_PDOP);
     238                    return pdopvalue.doubleValue();
     239                } else if (wp.attr.get(GpxConstants.PT_PDOP) instanceof Double) {
     240                    Double pdopvalue = (Double) wp.attr.get(GpxConstants.PT_PDOP);
     241                    return pdopvalue.doubleValue();
     242                }
     243            } else if (wp.attr.get(GpxConstants.PT_HDOP) != null) {
     244                if (wp.attr.get(GpxConstants.PT_HDOP) instanceof Float) {
     245                    Float hdopvalue = (Float) wp.attr.get(GpxConstants.PT_HDOP);
     246                    return hdopvalue.doubleValue();
     247                } else if (wp.attr.get(GpxConstants.PT_HDOP) instanceof Double) {
     248                    Double hdopvalue = (Double) wp.attr.get(GpxConstants.PT_HDOP);
     249                    return hdopvalue.doubleValue();
     250                }
     251            }
     252        }
     253        return null;
     254    }
     255
     256    static Double getGpsTrack(WayPoint wp) {
     257        if (wp != null) {
     258            String trackvalue = wp.getString(GpxConstants.PT_COURSE);
     259            Logging.debug("track angle value: {0}", trackvalue);
     260            if (!Utils.isEmpty(trackvalue)) {
     261                try {
     262                    return Double.valueOf(trackvalue);
     263                } catch (NumberFormatException e) {
     264                    Logging.warn(e);
     265                }
     266            }
     267        }
     268        return null;
     269    }
     270
     271    static String getGpsProcMethod(String prevGpsFixMode, final String curGpsFixMode,
     272                                    final List<String> positioningModes) {
     273        String gpsProcMethod = null;
     274        Integer lowestProcIndex = null;
     275        int lowestGnssModeIdx = 3; // 2d or higher index in positioningModes list are Gnss methods
     276        try {
     277            lowestProcIndex = Math.min(positioningModes.indexOf(prevGpsFixMode), positioningModes.indexOf(curGpsFixMode));
     278            if (lowestProcIndex < 0) {
     279                return null;
     280            }
     281            gpsProcMethod = "GNSS" + " " + positioningModes.get(lowestProcIndex).toUpperCase() + " " + "CORRELATION";
     282            if (lowestProcIndex < lowestGnssModeIdx) {
     283                gpsProcMethod = positioningModes.get(lowestProcIndex).toUpperCase() + " " + "CORRELATION";
     284            } else {
     285                gpsProcMethod = "GNSS" + " " + positioningModes.get(lowestProcIndex).toUpperCase() + " " + "CORRELATION";
     286            }
     287            gpsProcMethod = gpsProcMethod.replace("FLOAT RTK", "RTK_FLOAT");
     288            gpsProcMethod = gpsProcMethod.replace(" RTK ", " RTK_FIX ");
     289        } catch (ArrayIndexOutOfBoundsException ex) {
     290            Logging.warn(ex);
     291        }
     292        return gpsProcMethod;
     293    }
     294
     295    static Integer getGps2d3dMode(String prevGpsFixMode, final String curGpsFixMode,
     296                                final List<String> positioningModes) {
     297        Integer lowestMode = null;
     298        lowestMode = Math.min(positioningModes.indexOf(prevGpsFixMode), positioningModes.indexOf(curGpsFixMode));
     299        if (lowestMode > 3) {
     300            return 3;
     301        }
     302        if (lowestMode > 2) {
     303            return 2;
     304        }
     305        return null;
     306    }
     307
     308    // CHECKSTYLE.OFF: ParameterNumber
     309    private static int matchPoints(List<? extends GpxImageEntry>
     310                                        images,
     311                                        WayPoint prevWp,
     312                                        long prevWpTime,
     313                                        WayPoint curWp,
     314                                        long curWpTime,
     315                                        long offset,
     316                                        boolean interpolate,
     317                                        int tagTime,
     318                                        WayPoint nextWp,
     319                                        GpxImageDirectionPositionSettings dirpos,
     320                                        GpxImageDatumSettings datumSettings) {
    214321
    215322        final boolean isLast = nextWp == null;
     
    237344        Double speed = null;
    238345        Double prevElevation = null;
     346        Double prevHPosErr = null;
     347        Double prevGpsDop = null;
     348        Double prevGpsTrack = null;
     349        String prevGpsFixMode = null;
     350        //list of differential GPS mode
     351        //TODO move these lists in Gpx.Constants?
     352        final List<String> diffMode = Arrays.asList("dgps", "float rtk", "rtk");
     353        final List<String> positioningModes = Arrays.asList("none", "manual", "estimated", "2d", "3d", "dgps", "float rtk", "rtk");
     354
    239355
    240356        if (prevWp != null && interpolate) {
     
    245361            }
    246362            prevElevation = getElevation(prevWp);
     363            prevHPosErr = getHPosErr(prevWp);
     364            prevGpsDop = getGpsDop(prevWp);
     365            prevGpsTrack = getGpsTrack(prevWp);
     366            prevGpsFixMode = prevWp.getString(GpxConstants.PT_FIX);
    247367        }
    248368
    249369        final Double curElevation = getElevation(curWp);
     370        final Double curHPosErr = getHPosErr(curWp);
     371        final Double curGpsDop = getGpsDop(curWp);
     372        final Double curGpsTrack = getGpsTrack(curWp);
     373        final String curGpsFixMode = curWp.getString(GpxConstants.PT_FIX);
    250374
    251375        if (!interpolate || isLast) {
     
    267391                        curTmp.setPos(curWp.getCoor());
    268392                    }
     393                    //TODO fix this, nextWp doesn't exist here
    269394                    if (nextWp != null && dirpos.isSetImageDirection()) {
    270395                        double direction = curWp.bearing(nextWp);
     
    318443                        curTmp.setElevation(prevElevation + (curElevation - prevElevation) * timeDiff + dirpos.getElevationShift());
    319444                    }
     445
     446                    // Add exif GpsHPositioningerror interpolated value
     447                    if (curHPosErr != null && prevHPosErr != null) {
     448                        Double interpolatedValue = prevHPosErr + (curHPosErr - prevHPosErr) * timeDiff;
     449                        curTmp.setExifHPosErr(Math.round(interpolatedValue*10000)/10000.0);
     450                    }
     451
     452                    // Add exif GpsDifferentialMode
     453                    // Get previous and current waypoint differential. As no interpolation is possible,
     454                    // set differential mode to 0 if any waypoint isn't in differential mode.
     455                    if (prevGpsFixMode != null) {
     456                        if (diffMode.contains(prevGpsFixMode) && diffMode.contains(curGpsFixMode)) {
     457                            curTmp.setGpsDiffMode(1);
     458                        } else {
     459                            curTmp.setGpsDiffMode(0);
     460                        }
     461                    }
     462
     463                    // Add exif GpsMeasureMode
     464                    if (prevGpsFixMode != null && curGpsFixMode != null) {
     465                        Integer gps2d3dMode = getGps2d3dMode(prevGpsFixMode, curGpsFixMode, positioningModes);
     466                        if (gps2d3dMode != null) {
     467                            curTmp.setGps2d3dMode(gps2d3dMode);
     468                        }
     469                    }
     470                   
     471                    // Add exif GpsProcessingMethod. As no interpolation is possible,
     472                    // set processing method to the "lowest" previous and current processing method value.
     473                    if (prevGpsFixMode != null && curGpsFixMode != null) {
     474                        String gpsProcMethod = getGpsProcMethod(prevGpsFixMode, curGpsFixMode, positioningModes);                       
     475                        if (gpsProcMethod != null) {
     476                            curTmp.setExifGpsProcMethod(gpsProcMethod);
     477                        }
     478                    }
     479
     480                    // Add Exif GpsDop with interpolated GPS DOP value
     481                    if (curGpsDop != null && prevGpsDop != null) {
     482                        Double interpolatedValue = prevGpsDop + (curGpsDop - prevGpsDop) * timeDiff;
     483                        curTmp.setExifGpsDop(Math.round(interpolatedValue*100)/100.0);
     484                    }
     485
     486                    // Add Exif GpsTrack tag
     487                    if (dirpos.isSetGpxTrackDirection()) {
     488                        if (curGpsTrack != null && prevGpsTrack != null) {
     489                            curTmp.setExifGpsTrack(prevGpsTrack + (curGpsTrack - prevGpsTrack) * timeDiff);
     490                        }
     491                    }
     492                   
     493                    // Add GpsDatum tag
     494                    if (datumSettings.isSetImageGpsDatum()) {
     495                        if (diffMode.contains(prevGpsFixMode) && diffMode.contains(curGpsFixMode)) {
     496                            curTmp.setExifGpsDatum(datumSettings.getImageGpsDatum());
     497                        } else //without differential mode, datum is WGS-84
     498                            curTmp.setExifGpsDatum("WGS-84");
     499                    }
     500
    320501                    curTmp.setGpsTime(curImg.getExifInstant().minusMillis(offset));
    321502                    curTmp.flagNewGpsData();
     
    331512        return ret;
    332513    }
     514    // CHECKSTYLE.ON: ParameterNumber
    333515
    334516    private static double computeDirection(double direction, double angleOffset) {
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxImageCorrelationSettings.java

    r18065 r19387  
    1313    private final boolean forceTags;
    1414    private final GpxImageDirectionPositionSettings directionPositionSettings;
     15    private final GpxImageDatumSettings datumSettings;
    1516
    1617    /**
     
    2021     */
    2122    public GpxImageCorrelationSettings(long offset, boolean forceTags) {
    22         this(offset, forceTags, new GpxImageDirectionPositionSettings(false, 0, 0, 0, 0));
     23        this(offset, forceTags,
     24        new GpxImageDirectionPositionSettings(false, 0, false, 0, 0, 0),
     25        new GpxImageDatumSettings(false, null)
     26        );
    2327    }
    2428
     
    3135    public GpxImageCorrelationSettings(long offset, boolean forceTags,
    3236            GpxImageDirectionPositionSettings directionPositionSettings) {
     37        this(offset, forceTags, directionPositionSettings,
     38        new GpxImageDatumSettings(false, null));
     39    }
     40
     41    /**
     42     * Constructs a new {@code GpxImageCorrelationSettings}.
     43     * @param offset offset in milliseconds
     44     * @param forceTags force tagging of all photos, otherwise prefs are used
     45     * @param directionPositionSettings direction/position settings
     46     * @param datumSettings GPS datum settings
     47     * @since 19387 @datumSettings was added
     48     */
     49    public GpxImageCorrelationSettings(long offset, boolean forceTags,
     50            GpxImageDirectionPositionSettings directionPositionSettings,
     51            GpxImageDatumSettings datumSettings) {
    3352        this.offset = offset;
    3453        this.forceTags = forceTags;
    3554        this.directionPositionSettings = Objects.requireNonNull(directionPositionSettings);
     55        this.datumSettings = Objects.requireNonNull(datumSettings);
    3656    }
    37 
     57   
    3858    /**
    3959     * Returns the offset in milliseconds.
     
    6080    }
    6181
     82    /**
     83     * Returns the EXIF metadata datum settings.
     84     * @return the EXIF metadata datum settings
     85     * @since 19387
     86     */
     87    public GpxImageDatumSettings getDatumSettings() {
     88        return datumSettings;
     89    }
     90
    6291    @Override
    6392    public String toString() {
    6493        return "[offset=" + offset + ", forceTags=" + forceTags
    65                 + ", directionPositionSettings=" + directionPositionSettings + ']';
     94                + ", directionPositionSettings=" + directionPositionSettings
     95                + ", datumSettings=" + datumSettings + ']';
    6696    }
    6797}
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxImageDirectionPositionSettings.java

    r18065 r19387  
    1010    private final boolean setImageDirection;
    1111    private final double imageDirectionAngleOffset;
     12    private final boolean setGpxTrackDirection;
    1213    private final double shiftImageX;
    1314    private final double shiftImageY;
     
    1819     * @param setImageDirection determines if image direction must be set towards the next GPX waypoint
    1920     * @param imageDirectionAngleOffset direction angle offset in degrees
     21     * @param setGpxTrackDirection determines if image course direction must be set
    2022     * @param shiftImageX image shift on X axis relative to the direction in meters
    2123     * @param shiftImageY image shift on Y axis relative to the direction in meters
    2224     * @param elevationShift image elevation shift in meters
     25     * @since 19387 @setGpsTrackDirection was added
    2326     */
    2427    public GpxImageDirectionPositionSettings(
    25             boolean setImageDirection, double imageDirectionAngleOffset, double shiftImageX, double shiftImageY, double elevationShift) {
     28            boolean setImageDirection, double imageDirectionAngleOffset, boolean setGpxTrackDirection,
     29            double shiftImageX, double shiftImageY, double elevationShift) {
    2630        this.setImageDirection = setImageDirection;
    2731        this.imageDirectionAngleOffset = imageDirectionAngleOffset;
     32        this.setGpxTrackDirection = setGpxTrackDirection;
    2833        this.shiftImageX = shiftImageX;
    2934        this.shiftImageY = shiftImageY;
     
    4550    public double getImageDirectionAngleOffset() {
    4651        return imageDirectionAngleOffset;
     52    }
     53
     54    /**
     55     * Determines if GPS course direction must be set. Angle value is from the gpx trace.
     56     * @return {@code true} if image GPS course must be set
     57     * @since 19387
     58     */
     59    public boolean isSetGpxTrackDirection() {
     60        return setGpxTrackDirection;
    4761    }
    4862
     
    7488    public String toString() {
    7589        return "[setImageDirection=" + setImageDirection
    76                 + ", imageDirectionAngleOffset=" + imageDirectionAngleOffset + ", shiftImageX=" + shiftImageX
    77                 + ", shiftImageY=" + shiftImageY + ", elevationShift=" + elevationShift + ']';
     90                + ", imageDirectionAngleOffset=" + imageDirectionAngleOffset
     91                + ", setImageGpxTrackDirection=" + setGpxTrackDirection
     92                + ", shiftImageX=" + shiftImageX
     93                + ", shiftImageY=" + shiftImageY
     94                + ", elevationShift=" + elevationShift + ']';
    7895    }
    7996}
  • trunk/src/org/openstreetmap/josm/data/gpx/GpxImageEntry.java

    r19320 r19387  
    3333    private LatLon exifCoor;
    3434    private Double exifImgDir;
     35    private Double exifGpsTrack;
     36    private Double exifHPosErr;
     37    private Double exifGpsDop;
    3538    private Instant exifTime;
    3639    private Projections cameraProjection = Projections.UNKNOWN;
     
    5861    /** Elevation (altitude) in meters */
    5962    private Double elevation;
     63    /** GPS Differential mode */
     64    private Integer gpsDiffMode;
     65    /** GPS Measure mode */
     66    private Integer gps2d3dMode;
     67    /** GPS Datum */
     68    private String exifGpsDatum;
     69    /** GPS processing method */
     70    private String exifGpsProcMethod;
    6071    /** The time after correlation with a gpx track */
    6172    private Instant gpsTime;
     
    89100        exifCoor = other.exifCoor;
    90101        exifImgDir = other.exifImgDir;
     102        exifGpsTrack = other.exifGpsTrack;
     103        exifHPosErr = other.exifHPosErr;
     104        gpsDiffMode = other.gpsDiffMode;
     105        gps2d3dMode = other.gps2d3dMode;
     106        exifGpsDop = other.exifGpsDop;
     107        exifGpsDatum = other.exifGpsDatum;
     108        exifGpsProcMethod = other.exifGpsProcMethod;
    91109        exifTime = other.exifTime;
    92110        isNewGpsData = other.isNewGpsData;
     
    171189
    172190    /**
     191     * Return the GPS Differential mode value. The GPS Differential mode value from the temporary
     192     * copy is returned if that copy exists.
     193     * @return the differential mode value
     194     * @since 19387
     195     */
     196    @Override
     197    public Integer getGpsDiffMode() {
     198        if (tmp != null)
     199            return tmp.gpsDiffMode;
     200        return gpsDiffMode;
     201    }
     202
     203    /**
     204     * Return the GPS 2d or 3d mode value. The GPS mode value form the temporary
     205     * copy is returned if that copy exists.
     206     * @return the GPS 2d/3d mode value
     207     * @since 19387
     208     */
     209    @Override
     210    public Integer getGps2d3dMode() {
     211        if (tmp != null)
     212            return tmp.gps2d3dMode;
     213        return gps2d3dMode;
     214    }
     215
     216    /**
     217     * Return the GPS DOP value. The GPS DOP value from the temporary
     218     * copy is returned if that copy exists.
     219     * @return the DOP value
     220     * @since 19387
     221     */
     222    @Override
     223    public Double getExifGpsDop() {
     224        if (tmp != null)
     225            return tmp.exifGpsDop;
     226        return exifGpsDop;
     227    }
     228
     229    /**
     230     * Return the exif GPS coordinates datum value.
     231     * @return The datum value
     232     * @since 19387
     233     */
     234    @Override
     235    public String getExifGpsDatum() {
     236        if (tmp != null)
     237            return tmp.exifGpsDatum;
     238        return exifGpsDatum;
     239    }
     240
     241    /**
     242     * Return the exif GPS processing method string
     243     * @return the processing method string
     244     * @since 19387
     245     */
     246    @Override
     247    public String getExifGpsProcMethod() {
     248        if (tmp != null)
     249            return tmp.exifGpsProcMethod;
     250        return exifGpsProcMethod;
     251    }
     252
     253    /**
    173254     * Returns the GPS time value. The GPS time value from the temporary copy
    174255     * is returned if that copy exists.
     
    272353            return tmp.exifImgDir;
    273354        return exifImgDir;
     355    }
     356   
     357    /**
     358     * Convenient way to determine if this entry has a EXIF GPS track angle value,
     359     * without the cost of building a defensive copy.
     360     * @return {@code true} if this entry has a EXIF track angle value
     361     * @since 19387
     362     */
     363    @Override
     364    public Double getExifGpsTrack() {
     365        if (tmp != null)
     366            return tmp.exifGpsTrack;
     367        return exifGpsTrack;
     368    }
     369
     370    /**
     371     * Convenient way to determine if this entry has a EXIF GPS horizontal positionning error value,
     372     * without the cost of building a defensive copy.
     373     * @return {@code true} if this entry has a EXIF GPS horizontal positionning error value
     374     * @since 19387
     375     */
     376    @Override
     377    public Double getExifHPosErr() {
     378        if (tmp != null)
     379            return tmp.exifHPosErr;
     380        return exifHPosErr;
    274381    }
    275382
     
    347454
    348455    /**
     456     * Sets GPS Differential mode.
     457     * @param gpsDiffMode GPS Differential mode
     458     * @since 19387
     459     */
     460    @Override
     461    public void setGpsDiffMode(Integer gpsDiffMode) {
     462        this.gpsDiffMode = gpsDiffMode;
     463    }
     464
     465    /**
     466     * Sets GPS 2d/3d mode.
     467     * @param gps2d3dMode GPS 2d/3d mode value
     468     * @since 19387
     469     */
     470    @Override
     471    public void setGps2d3dMode(Integer gps2d3dMode) {
     472        this.gps2d3dMode = gps2d3dMode;
     473    }
     474
     475    /**
     476     * Sets GPS DOP value.
     477     * @param exifGpsDop GPS DOP value
     478     * @since 19387
     479     */
     480    @Override
     481    public void setExifGpsDop(Double exifGpsDop) {
     482        this.exifGpsDop = exifGpsDop;
     483    }
     484
     485    /**
     486     * Sets the GPS Datum.
     487     * @param exifGpsDatum GPS Datum
     488     * @since 19387
     489     */
     490    @Override
     491    public void setExifGpsDatum(String exifGpsDatum) {
     492        this.exifGpsDatum = exifGpsDatum;
     493    }
     494
     495    /**
     496     * Sets the GPS Processing Method.
     497     * @param exifGpsProcMethod GPS Processing Method
     498     * @since 19387
     499     */
     500    @Override
     501    public void setExifGpsProcMethod(String exifGpsProcMethod) {
     502        this.exifGpsProcMethod = exifGpsProcMethod;
     503    }
     504
     505    /**
    349506     * Sets associated file.
    350507     * @param file associated file
     
    411568    public void setExifImgDir(Double exifDir) {
    412569        this.exifImgDir = exifDir;
     570    }
     571
     572    /**
     573     * Sets the exif GPS track (move direction angle)
     574     * @param exifGpsTrack the exif GPS track angle
     575     * @since 19387
     576     */
     577    @Override
     578    public void setExifGpsTrack(Double exifGpsTrack) {
     579        this.exifGpsTrack = exifGpsTrack;
     580    }
     581
     582    /**
     583     * Sets the exif horizontal positioning error
     584     * @param exifHposErr the Exif horizontal positionning error
     585     * @since 19387
     586     */
     587    @Override
     588    public void setExifHPosErr(Double exifHPosErr) {
     589        this.exifHPosErr = exifHPosErr;
    413590    }
    414591
     
    508685    public int hashCode() {
    509686        return Objects.hash(height, width, isNewGpsData,
    510             elevation, exifCoor, exifGpsTime, exifImgDir, exifOrientation, exifTime,
    511             iptcCaption, iptcHeadline, iptcKeywords, iptcObjectName,
    512             file, gpsTime, pos, speed, tmp, cameraProjection);
     687            elevation, exifCoor, exifGpsTime, exifImgDir, exifGpsTrack, exifHPosErr,
     688            exifGpsDop, gpsDiffMode, gps2d3dMode, exifGpsDatum, exifGpsProcMethod,
     689            exifOrientation, exifTime, iptcCaption, iptcHeadline, iptcKeywords,
     690            iptcObjectName, file, gpsTime, pos, speed, tmp, cameraProjection);
    513691    }
    514692
     
    527705            && Objects.equals(exifGpsTime, other.exifGpsTime)
    528706            && Objects.equals(exifImgDir, other.exifImgDir)
     707            && Objects.equals(exifGpsTrack, other.exifGpsTrack)
     708            && Objects.equals(exifHPosErr, other.exifHPosErr)
     709            && Objects.equals(gpsDiffMode, other.gpsDiffMode)
     710            && Objects.equals(gps2d3dMode, other.gps2d3dMode)
     711            && Objects.equals(exifGpsDop, other.exifGpsDop)
     712            && Objects.equals(exifGpsDatum, other.exifGpsDatum)
     713            && Objects.equals(exifGpsProcMethod, other.exifGpsProcMethod)
    529714            && Objects.equals(exifOrientation, other.exifOrientation)
    530715            && Objects.equals(exifTime, other.exifTime)
     
    571756     * temporary variable is deleted.
    572757     * @see #discardTmp()
     758     * @since 19387 exifGpsTrack, exifHPosErr, gpsDiffMode, gps2d3dMode, exifGpsDop, exifGpsDatum, exifGpsProcMethod added
    573759     */
    574760    public void applyTmp() {
     
    579765            gpsTime = tmp.gpsTime;
    580766            exifImgDir = tmp.exifImgDir;
     767            exifGpsTrack = tmp.exifGpsTrack;
     768            exifHPosErr = tmp.exifHPosErr;
     769            gpsDiffMode = tmp.gpsDiffMode;
     770            gps2d3dMode = tmp.gps2d3dMode;
     771            exifGpsDop = tmp.exifGpsDop;
     772            exifGpsDatum = tmp.exifGpsDatum;
     773            exifGpsProcMethod = tmp.exifGpsProcMethod;
    581774            isNewGpsData = isNewGpsData || tmp.isNewGpsData;
    582775            tmp = null;
  • trunk/src/org/openstreetmap/josm/data/imagery/street_level/IImageEntry.java

    r18599 r19387  
    220220
    221221    /**
     222     * Return the GPS Differential mode value. The differential mode value from the temporary
     223     * copy is returned if that copy exists.
     224     * @return the fix mode value
     225     * @since 19387
     226     */
     227    Integer getGpsDiffMode();
     228
     229    /**
     230     * Return the GPS 2d/3d mode value. The 2d/3d mode value from the temporary
     231     * copy is returned if that copy exists.
     232     * @return the 2d/3d mode value
     233     * @since 19387
     234     */
     235    Integer getGps2d3dMode();
     236
     237    /**
     238     * Return the GPS DOP value. The GPS DOP value from the temporary
     239     * copy is return if that copy exists.
     240     * @return the GPS DOP value
     241     * @since 19387
     242     */
     243    Double getExifGpsDop();
     244
     245    /**
     246     * Return the GPS datum value. The GPS datum value from the temporary
     247     * copy is return if that copy exists.
     248     * @return the GPS datum value
     249     * @since 19387
     250     */
     251    String getExifGpsDatum();
     252
     253    /**
     254     * Return the GPS processing method. The processing method value from the temporary
     255     * copy is return if that copy exists.
     256     * @return the GPS processing method
     257     * @since 19387
     258     */
     259    String getExifGpsProcMethod();
     260
     261    /**
    222262     * Returns the image direction. The image direction from the temporary
    223263     * copy is returned if that copy exists.
     
    225265     */
    226266    Double getExifImgDir();
    227 
     267   
     268    /**
     269     * Returns the image GPS track direction. The GPS track direction from the temporary
     270     * copy is returned if that copy exists.
     271     * @return the image GPS track direction angle
     272     * @since 19387
     273     */
     274    Double getExifGpsTrack();
     275
     276    /**
     277     * Returns the image horizontal positionning error. The image positionning error
     278     * from the temporary copy is returned if that copy exists.
     279     * @return the image horizontal positionning error
     280     * @since 19387
     281     */
     282    Double getExifHPosErr();
     283   
    228284    /**
    229285     * Convenient way to determine if this entry has a EXIF time, without the cost of building a defensive copy.
     
    253309
    254310    /**
     311     * Returns the Exif GPS Time value. The Exif GPS time value from the temporary copy
     312     * is returned if that copy exists.
     313     * @return the Exif GPS time value
     314     * @since 19387
     315     */
     316    Instant getExifGpsInstant();
     317
     318    /**
    255319     * Returns the IPTC caption.
    256320     * @return the IPTC caption
  • trunk/src/org/openstreetmap/josm/gui/layer/OsmDataLayer.java

    r19271 r19387  
    979979        addStringIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_TYPE, null, null);
    980980
     981        // Angle info
     982        addDoubleIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_COURSE, "gps:course");
     983
    981984        // Accuracy info
    982985        addStringIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_FIX, "gps:fix", null);
     
    985988        addDoubleIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_VDOP, "gps:vdop");
    986989        addDoubleIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_PDOP, "gps:pdop");
     990        addDoubleIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_STD_HDEV, "gps:stdhdev");
     991        addDoubleIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_STD_VDEV, "gps:stdvdev");
    987992        addDoubleIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_AGEOFDGPSDATA, "gps:ageofdgpsdata");
    988993        addIntegerIfPresent(wpt, n, gpxPrefix, GpxConstants.PT_DGPSID, "gps:dgpsid");
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/CorrelateGpxWithImages.java

    r19327 r19387  
    5454import org.openstreetmap.josm.data.gpx.GpxImageCorrelation;
    5555import org.openstreetmap.josm.data.gpx.GpxImageCorrelationSettings;
     56import org.openstreetmap.josm.data.gpx.GpxImageDatumSettings;
    5657import org.openstreetmap.josm.data.gpx.GpxTimeOffset;
    5758import org.openstreetmap.josm.data.gpx.GpxTimezone;
     
    169170                Config.getPref().put("geoimage.delta", delta.formatOffset());
    170171                Config.getPref().putBoolean("geoimage.showThumbs", yLayer.useThumbs);
     172                Config.getPref().put("geoimage.datum", tfDatum.getText());
    171173
    172174                yLayer.useThumbs = cbShowThumbs.isSelected();
     
    247249    private ExtendedDialog syncDialog;
    248250    private JPanel outerPanel;
     251    private JPanel expertPanel;
    249252    private JosmComboBox<GpxDataWrapper> cbGpx;
    250253    private JButton buttonSupport;
     
    254257    private JCheckBox cbTaggedImg;
    255258    private JCheckBox cbShowThumbs;
     259    private JSeparator sepExtendedTags;
     260    private JLabel labelExtTags;
     261    private JLabel labelDatum;
    256262    private JLabel statusBarText;
    257263    private JSeparator sepDirectionPosition;
    258264    private ImageDirectionPositionPanel pDirectionPosition;
     265    private JCheckBox cbAddGpsDatum;
     266    private JosmTextField tfDatum;
    259267
    260268    // remember the last number of matched photos
     
    473481    }
    474482
     483    static String loadGpsDatum() {
     484        String gpsDatum = Config.getPref().get("geoimage.datum", "WGS-84");
     485        return gpsDatum;
     486    }
     487
    475488    @Override
    476489    public void actionPerformed(ActionEvent ae) {
     
    542555
    543556        int y = 0;
    544         GBC gbc = GBC.eol();
    545         gbc.gridx = 0;
    546         gbc.gridy = y++;
    547         panelTf.add(panelCb, gbc);
    548 
    549         gbc = GBC.eol().fill(GridBagConstraints.HORIZONTAL).insets(0, 0, 0, 12);
    550         gbc.gridx = 0;
    551         gbc.gridy = y++;
     557        panelTf.add(panelCb, GBC.eol().grid(0, y++));
     558
     559        GBC gbc = GBC.eol().grid(0, y++).fill(GridBagConstraints.HORIZONTAL).insets(0, 0, 0, 12);
    552560        panelTf.add(new JSeparator(SwingConstants.HORIZONTAL), gbc);
    553561
    554         gbc = GBC.std();
    555         gbc.gridx = 0;
    556         gbc.gridy = y;
    557         panelTf.add(new JLabel(tr("Timezone: ")), gbc);
    558 
    559         gbc = GBC.std().fill(GridBagConstraints.HORIZONTAL);
    560         gbc.gridx = 1;
    561         gbc.gridy = y++;
     562        panelTf.add(new JLabel(tr("Timezone: ")), GBC.std(0, y));
     563
     564        gbc = GBC.std(1, y++).fill(GridBagConstraints.HORIZONTAL);
    562565        gbc.weightx = 1.;
    563566        panelTf.add(tfTimezone, gbc);
    564567
    565         gbc = GBC.std();
    566         gbc.gridx = 0;
    567         gbc.gridy = y;
     568        gbc = GBC.std(0, y);
    568569        panelTf.add(new JLabel(tr("Offset:")), gbc);
    569570
    570         gbc = GBC.std().fill(GridBagConstraints.HORIZONTAL);
    571         gbc.gridx = 1;
    572         gbc.gridy = y++;
     571        gbc = GBC.std(1, y++).fill(GridBagConstraints.HORIZONTAL);
    573572        gbc.weightx = 1.;
    574573        panelTf.add(tfOffset, gbc);
    575574
    576         gbc = GBC.std().insets(5, 5, 5, 5);
    577         gbc.gridx = 2;
    578         gbc.gridy = y-2;
    579         gbc.gridheight = 2;
    580         gbc.gridwidth = 2;
     575        gbc = GBC.std(2, y-2).insets(5, 5, 5, 5).span(2, 2);
    581576        gbc.fill = GridBagConstraints.BOTH;
    582577        gbc.weightx = 0.5;
    583578        panelTf.add(buttonViewGpsPhoto, gbc);
    584579
    585         gbc = GBC.std().fill(GridBagConstraints.BOTH).insets(5, 5, 5, 5);
    586         gbc.gridx = 1;
    587         gbc.gridy = y++;
     580        gbc = GBC.std(1, y++).fill(GridBagConstraints.BOTH).insets(5, 5, 5, 5);
    588581        gbc.weightx = 0.5;
    589582        panelTf.add(buttonAdvanced, gbc);
     
    595588        panelTf.add(buttonAdjust, gbc);
    596589
    597         gbc = GBC.eol().fill(GridBagConstraints.HORIZONTAL).insets(0, 12, 0, 0);
    598         gbc.gridx = 0;
    599         gbc.gridy = y++;
     590        gbc = GBC.eol().grid(0, y++).fill(GridBagConstraints.HORIZONTAL).insets(0, 12, 0, 0);
    600591        panelTf.add(new JSeparator(SwingConstants.HORIZONTAL), gbc);
    601 
    602         gbc = GBC.eol();
    603         gbc.gridx = 0;
    604         gbc.gridy = y++;
    605         panelTf.add(labelPosition, gbc);
    606 
    607         gbc = GBC.eol();
    608         gbc.gridx = 1;
    609         gbc.gridy = y++;
    610         panelTf.add(cbExifImg, gbc);
    611 
    612         gbc = GBC.eol();
    613         gbc.gridx = 1;
    614         gbc.gridy = y++;
    615         panelTf.add(cbTaggedImg, gbc);
    616 
    617         gbc = GBC.eol();
    618         gbc.gridx = 0;
    619         gbc.gridy = y++;
    620         panelTf.add(cbShowThumbs, gbc);
    621 
     592        panelTf.add(labelPosition, GBC.eol().grid(0, y++));
     593        panelTf.add(cbExifImg, GBC.eol().grid(1, y++));
     594        panelTf.add(cbTaggedImg, GBC.eol().grid(1, y++));
     595        panelTf.add(cbShowThumbs, GBC.eol().grid(0, y++));
     596
     597        //Image direction and position offset GUI
    622598        gbc = GBC.eol().fill(GridBagConstraints.HORIZONTAL).insets(0, 12, 0, 0);
    623599        sepDirectionPosition = new JSeparator(SwingConstants.HORIZONTAL);
     
    631607        panelTf.add(pDirectionPosition, gbc);
    632608
     609        //Extended tags GUI panel
     610        expertPanel = new JPanel(new GridBagLayout());
     611        gbc = GBC.eol().grid(0, 0).fill(GridBagConstraints.HORIZONTAL).insets(0, 12, 0, 0);
     612        sepExtendedTags = new JSeparator(SwingConstants.HORIZONTAL);
     613        expertPanel.add(sepExtendedTags, gbc);
     614
     615        labelExtTags = new JLabel(tr("Extended tags"));
     616        cbAddGpsDatum = new JCheckBox(tr("Set datum for images coordinates"));
     617        cbAddGpsDatum.addActionListener(e -> tfDatum.setEnabled(!tfDatum.isEnabled()));
     618
     619        labelDatum = new JLabel(tr("Datum: "));
     620        //TODO An AutoCompComboBox would be nice to list the recent datum values. I don't have the skill to add it.
     621        tfDatum = new JosmTextField(loadGpsDatum(), 8);
     622        tfDatum.setToolTipText(tr("<html>Enter the datum for your images coordinates. Default value is WGS-84.<br>" +
     623                                "For RTK it could be your local CRS epsg code.<br>(e.g. EPSG:9782 for France mainland.)</html>"));
     624        tfDatum.setEnabled(false);
     625
     626        expertPanel.add(labelExtTags, GBC.eol().grid(0, 1));
     627        expertPanel.add(cbAddGpsDatum, GBC.eol().grid(0, 2));
     628        expertPanel.add(labelDatum, GBC.std(1, 3));
     629        expertPanel.add(tfDatum, GBC.eol().grid(2, 3));
     630
     631        //Add expertPanel to panelTf
     632        gbc = GBC.eol().fill(GridBagConstraints.HORIZONTAL).insets(0, 12, 0, 0);
     633        gbc.gridy = y++;
     634        panelTf.add(expertPanel, gbc);
     635       
    633636        final JPanel statusPanel = new JPanel(new FlowLayout(FlowLayout.CENTER, 10, 10));
    634637        statusPanel.setBorder(BorderFactory.createLoweredBevelBorder());
     
    652655        cbExifImg.addItemListener(statusBarUpdaterWithRepaint);
    653656        cbTaggedImg.addItemListener(statusBarUpdaterWithRepaint);
     657        cbAddGpsDatum.addItemListener(statusBarUpdaterWithRepaint);
     658        tfDatum.getDocument().addDocumentListener(statusBarUpdater);
    654659        pDirectionPosition.addChangeListenerOnComponents(statusBarUpdaterWithRepaint);
    655660        pDirectionPosition.addItemListenerOnComponents(statusBarUpdaterWithRepaint);
     
    679684    }
    680685
     686    public GpxImageDatumSettings getSettings() {
     687        return new GpxImageDatumSettings(
     688            cbAddGpsDatum.isSelected(),
     689            tfDatum.getText());
     690    }
     691
    681692    @Override
    682693    public void expertChanged(boolean isExpert) {
     
    689700        if (pDirectionPosition != null) {
    690701            pDirectionPosition.setVisible(isExpert);
     702        }
     703        if (expertPanel != null) {
     704            expertPanel.setVisible(isExpert);
    691705        }
    692706        if (syncDialog != null) {
     
    787801            lastNumMatched = GpxImageCorrelation.matchGpxTrack(dateImgLst, selGpx.data,
    788802                    pDirectionPosition.isVisible() ?
    789                             new GpxImageCorrelationSettings(offsetMs, forceTags, pDirectionPosition.getSettings()) :
     803                            new GpxImageCorrelationSettings(offsetMs, forceTags, pDirectionPosition.getSettings(),
     804                                                            new GpxImageDatumSettings(cbAddGpsDatum.isSelected(), tfDatum.getText())) :
    790805                            new GpxImageCorrelationSettings(offsetMs, forceTags));
    791806
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageDirectionPositionPanel.java

    r18078 r19387  
    2929    private final JCheckBox cChangeImageDirection = new JCheckBox();
    3030    private final JSpinner sOffsetDegrees = new JSpinner(new SpinnerNumberModel(0, -360, 360, 1));
     31    private final JCheckBox cSetGpxTrackTag = new JCheckBox();
    3132
    3233    private final JSpinner sX = new JSpinner(new SpinnerNumberModel(0.0, -50.0, 50.0, 0.1));
     
    3839     * @param changeDirectionText the text displayed for the change image direction combobox
    3940     */
    40     protected ImageDirectionPositionPanel(String changeDirectionText) {
     41    protected ImageDirectionPositionPanel(String changeDirectionText, boolean hideGpxTrack) {
    4142        super(new GridBagLayout());
    4243
     
    4647        addSetting(tr("Offset angle in degrees:"), sOffsetDegrees);
    4748        sOffsetDegrees.setEnabled(false);
     49        if (!hideGpxTrack) {
     50            cChangeImageDirection.addActionListener(e -> cSetGpxTrackTag.setEnabled(!cSetGpxTrackTag.isEnabled()));
     51            cSetGpxTrackTag.setText(tr("Set image course direction (from gpx track)"));
     52            add(cSetGpxTrackTag, GBC.eol().insets(0, 0, 0, 5));
     53            cSetGpxTrackTag.setEnabled(false);
     54        }
    4855
    4956        add(new JSeparator(SwingConstants.HORIZONTAL),
     
    6269     */
    6370    public static ImageDirectionPositionPanel forGpxTrace() {
    64         return new ImageDirectionPositionPanel(tr("Set image direction towards the next GPX waypoint"));
     71        return new ImageDirectionPositionPanel(tr("Set image direction towards the next GPX waypoint"), false);
    6572    }
    6673
     
    7077     */
    7178    public static ImageDirectionPositionPanel forImageSequence() {
    72         return new ImageDirectionPositionPanel(tr("Set image direction towards the next one"));
     79        return new ImageDirectionPositionPanel(tr("Set image direction towards the next one"), true);
    7380    }
    7481
     
    8794                cChangeImageDirection.isSelected(),
    8895                (Integer) sOffsetDegrees.getValue(),
     96                cSetGpxTrackTag.isSelected(),
    8997                (Double) sX.getValue(),
    9098                (Double) sY.getValue(),
     
    110118    public void addItemListenerOnComponents(ItemListener listener) {
    111119        cChangeImageDirection.addItemListener(listener);
     120        cSetGpxTrackTag.addItemListener(listener);
    112121    }
    113122
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageMetadata.java

    r19249 r19387  
    117117
    118118    /**
    119      * Get the exif coordinates
     119     * Get the EXIF coordinates
    120120     * @return The location of the image
    121121     */
     
    123123
    124124    /**
    125      * Get the exif direction
     125     * Get the EXIF direction
    126126     * @return The image direction
    127127     */
     
    129129
    130130    /**
    131      * Get the last time the source was modified
     131     * Get the EXIF GPS track direction.
     132     * @return The GPS track direction
     133     * @since 19387
     134     */
     135    Double getExifGpsTrack();
     136
     137    /**
     138     * Get the EXIF Horizontal positioning error.
     139     * @return The image horizontal positioning error
     140     * @since 19387
     141     */
     142    Double getExifHPosErr();
     143
     144    /**
     145     * Get the GPS Differential mode.
     146     * @return The image gnss fix mode
     147     * @since 19387
     148     */
     149    Integer getGpsDiffMode();
     150   
     151    /**
     152     * Get the GPS 2d/3d mode.
     153     * @return The image gnss 2d/3d mode
     154     * @since 19387
     155     */
     156    Integer getGps2d3dMode();
     157
     158    /**
     159     * Get the EXIF GPS DOP value.
     160     * @return The image GPS DOP value
     161     * @since 19387
     162     */
     163    Double getExifGpsDop();
     164
     165    /**
     166     * Get the GPS datum value.
     167     * @return The image GPS datum value
     168     * @since 19387
     169     */
     170    String getExifGpsDatum();
     171
     172    /**
     173     * Get the EXIF GPS processing method.
     174     * @return The image GPS processing method
     175     * @since 19387
     176     */
     177    String getExifGpsProcMethod();
     178
     179    /**
     180     * Get the last time the source was modified.
    132181     * @return The last time the source was modified
    133182     */
     
    194243
    195244    /**
    196      * Set the exif coordinates
    197      * @param exifCoor The exif coordinates
     245     * Sets the EXIF coordinates
     246     * @param exifCoor The EXIF coordinates
    198247     */
    199248    void setExifCoor(ILatLon exifCoor);
    200249
    201250    /**
    202      * Set the exif direction
     251     * Sets the EXIF direction
    203252     * @param exifDir The direction
    204253     */
    205254    void setExifImgDir(Double exifDir);
     255
     256    /**
     257     * Sets the EXIF GPS track direction.
     258     * @param exifGpsTrack The GPS track direction
     259     * @since 19387
     260     */
     261    void setExifGpsTrack(Double exifGpsTrack);
     262
     263    /**
     264     * Sets the EXIF horizontal positioning error.
     265     * @param exifHposErr the EXIF horizontal positionning error
     266     * @since 19387
     267     */
     268    void setExifHPosErr(Double exifHPosErr);
     269
     270    /**
     271     * Sets the EXIF GPS DOP value.
     272     * @param exifGpsDop the EXIF GPS DOP value
     273     * @since 19387
     274     */
     275    void setExifGpsDop(Double exifGpsDop);
     276
     277    /**
     278     * Sets the GPS Differential mode.
     279     * @param gpsDiffMode GPS Differential mode
     280     * @since 19387
     281     */
     282    void setGpsDiffMode(Integer gpsDiffMode);
     283
     284    /**
     285     * Sets the GPS 2d/3d mode.
     286     * @param gps2d3dMode GPS 2d/3d mode
     287     * @since 19387
     288     */
     289    void setGps2d3dMode(Integer gps2d3dMode);
     290
     291    /**
     292     * Sets the GPS datum value.
     293     * @param exifGpsDatum GPS datum
     294     * @since 19387
     295     */
     296    void setExifGpsDatum(String exifGpsDatum);
     297
     298    /**
     299     * Sets the GPS processing method.
     300     * @param exifGpsProcMethod GPS processing method
     301     * @since 19387
     302     */
     303    void setExifGpsProcMethod(String exifGpsProcMethod);
    206304
    207305    /**
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageUtils.java

    r18592 r19387  
    192192        }
    193193
     194        try {
     195            ifNotNull(ExifReader.readGpsTrackDirection(dirGps), image::setExifGpsTrack);
     196        } catch (IndexOutOfBoundsException ex) {
     197            Logging.debug(ex);
     198        }
     199
     200        try {
     201            ifNotNull(ExifReader.readHpositioningError(dirGps), image::setExifHPosErr);
     202        } catch (IndexOutOfBoundsException ex) {
     203            Logging.debug(ex);
     204        }
     205       
     206        try {
     207            ifNotNull(ExifReader.readGpsDiffMode(dirGps), image::setGpsDiffMode);
     208        } catch (IndexOutOfBoundsException ex) {
     209            Logging.debug(ex);
     210        }
     211       
     212        try {
     213            ifNotNull(ExifReader.readGpsMeasureMode(dirGps), image::setGps2d3dMode);
     214        } catch (IndexOutOfBoundsException ex) {
     215            Logging.debug(ex);
     216        }
     217
     218        try {
     219            ifNotNull(ExifReader.readGpsDop(dirGps), image::setExifGpsDop);
     220        } catch (IndexOutOfBoundsException ex) {
     221            Logging.debug(ex);
     222        }
     223
     224        try {
     225            ifNotNull(ExifReader.readGpsDatum(dirGps), image::setExifGpsDatum);
     226        } catch (IndexOutOfBoundsException ex) {
     227            Logging.debug(ex);
     228        }
     229
     230        try {
     231            ifNotNull(ExifReader.readGpsProcessingMethod(dirGps), image::setExifGpsProcMethod);
     232        } catch (IndexOutOfBoundsException ex) {
     233            Logging.debug(ex);
     234        }
     235       
    194236        ifNotNull(dirGps.getGpsDate(), d -> image.setExifGpsTime(d.toInstant()));
    195237    }
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/ImageViewerDialog.java

    r19266 r19387  
    8989    private final ImageZoomAction imageZoomAction = new ImageZoomAction();
    9090    private final ImageCenterViewAction imageCenterViewAction = new ImageCenterViewAction();
     91    private final ImageExtendedInfoAction imageExtendedInfoAction = new ImageExtendedInfoAction();
    9192    private final ImageNextAction imageNextAction = new ImageNextAction();
    9293    private final ImageRemoveAction imageRemoveAction = new ImageRemoveAction();
     
    104105    private Future<?> imgLoadingFuture;
    105106    private boolean centerView;
     107    private boolean extendedImgInfo;
    106108
    107109    // Only one instance of that class is present at one time
     
    164166    private JButton btnDeleteFromDisk;
    165167    private JToggleButton tbCentre;
     168    private JToggleButton tbImgExtInfo;
    166169    /** The layer tab (used to select images when multiple layers provide images, makes for easy switching) */
    167170    private final HideableTabbedPane layers = new HideableTabbedPane();
     
    235238        tbCentre.setPreferredSize(buttonDim);
    236239
     240        extendedImgInfo = Config.getPref().getBoolean("geoimage.viewer.extendedinfo", false);
     241        tbImgExtInfo = new JToggleButton(imageExtendedInfoAction);
     242        tbImgExtInfo.setSelected(extendedImgInfo);
     243        tbImgExtInfo.setPreferredSize(buttonDim);
     244
    237245        JButton btnZoomBestFit = new JButton(imageZoomAction);
    238246        btnZoomBestFit.setPreferredSize(buttonDim);
     
    243251        JPanel buttons = new JPanel();
    244252        addButtonGroup(buttons, this.btnFirst, this.btnPrevious, this.btnNext, this.btnLast);
    245         addButtonGroup(buttons, this.tbCentre, btnZoomBestFit);
     253        addButtonGroup(buttons, this.tbCentre, btnZoomBestFit, this.tbImgExtInfo);
    246254        addButtonGroup(buttons, this.btnDelete, this.btnDeleteFromDisk);
    247255        addButtonGroup(buttons, this.btnCopyPath, this.btnOpenExternal);
     
    584592    }
    585593
     594    private class ImageExtendedInfoAction extends JosmAction {
     595        ImageExtendedInfoAction() {
     596            super(null, new ImageProvider("info"), tr("Display image extended metadata"), Shortcut.registerShortcut(
     597                    "geoimage:extendedinfos", tr(GEOIMAGE_FILLER, tr("Toggle Osd extended informations")),
     598                    KeyEvent.CHAR_UNDEFINED, Shortcut.NONE),
     599            false, null, false);
     600        }
     601
     602        @Override
     603        public void actionPerformed(ActionEvent e) {
     604            final JToggleButton button = (JToggleButton) e.getSource();
     605            extendedImgInfo = button.isEnabled() && button.isSelected();
     606            Config.getPref().putBoolean("geoimage.viewer.extendedinfo", extendedImgInfo);
     607            refresh(false);
     608        }
     609    }
     610   
    586611    private class ImageRemoveAction extends JosmAction {
    587612        ImageRemoveAction() {
     
    10001025            osd.append(tr("\nSpeed: {0} km/h", Math.round(entry.getSpeed())));
    10011026        }
    1002         if (entry.getExifImgDir() != null) {
    1003             osd.append(tr("\nDirection {0}\u00b0", Math.round(entry.getExifImgDir())));
    1004         }
    1005 
    10061027        DateTimeFormatter dtf = DateUtils.getDateTimeFormatter(FormatStyle.SHORT, FormatStyle.MEDIUM)
    1007                 // Set timezone to UTC since UTC is assumed when parsing the EXIF timestamp,
    1008                 // see see org.openstreetmap.josm.tools.ExifReader.readTime(com.drew.metadata.Metadata)
    1009                 .withZone(ZoneOffset.UTC);
    1010 
     1028                    // Set timezone to UTC since UTC is assumed when parsing the EXIF timestamp,
     1029                    // see see org.openstreetmap.josm.tools.ExifReader.readTime(com.drew.metadata.Metadata)
     1030                    .withZone(ZoneOffset.UTC);
    10111031        if (entry.hasExifTime()) {
    1012             osd.append(tr("\nEXIF time: {0}", dtf.format(entry.getExifInstant())));
    1013         }
    1014         if (entry.hasGpsTime()) {
    1015             osd.append(tr("\nGPS time: {0}", dtf.format(entry.getGpsInstant())));
     1032            if (Config.getPref().getBoolean("geoimage.viewer.extendedinfo", false)) {
     1033                osd.append(tr("\nEXIF DTO time: {0}", dtf.format(entry.getExifInstant())));
     1034            } else {
     1035                osd.append(tr("\nEXIF time: {0}", dtf.format(entry.getExifInstant())));       
     1036            }
     1037        }
     1038
     1039        if (Config.getPref().getBoolean("geoimage.viewer.extendedinfo", false)) {
     1040            if (entry.getExifGpsInstant() != null) {
     1041                osd.append(tr("\nEXIF GPS time: {0}", dtf.format(entry.getExifGpsInstant())));
     1042            }
     1043            if (entry.hasGpsTime()) {
     1044                osd.append(tr("\nCorr GPS time: {0}", dtf.format(entry.getGpsInstant())));
     1045            }           
     1046            if (entry.getExifImgDir() != null) {
     1047                osd.append(tr("\nDirection {0}\u00b0", Math.round(entry.getExifImgDir())));
     1048            }
     1049            if (entry.getExifGpsTrack() != null) {
     1050                osd.append(tr("\nGPS direction: {0}\u00b0", Math.round(entry.getExifGpsTrack())));
     1051            }
     1052            if (entry.getExifHPosErr() != null) {
     1053                osd.append(tr("\nHpos errror: {0}m", entry.getExifHPosErr()));
     1054            }
     1055            if (entry.getGps2d3dMode() != null) {
     1056                osd.append(tr("\n2d/3d mode: {0}d", entry.getGps2d3dMode()));
     1057            }
     1058            if (entry.getGpsDiffMode() != null) {
     1059                osd.append(tr("\nDifferential: {0}", entry.getGpsDiffMode()));
     1060            }
     1061            if (entry.getExifGpsDop() != null) {
     1062                osd.append(tr("\nDOP: {0}", entry.getExifGpsDop()));
     1063            }
     1064            if (entry.getExifGpsDatum() != null) {
     1065                osd.append(tr("\nDatum: {0}", entry.getExifGpsDatum().toString()));
     1066            }
     1067            if (entry.getExifGpsProcMethod() != null) {
     1068                osd.append(tr("\nProc. method: {0}", entry.getExifGpsProcMethod().toString()));
     1069            }
    10161070        }
    10171071        Optional.ofNullable(entry.getIptcCaption()).map(s -> tr("\nCaption: {0}", s)).ifPresent(osd::append);
     
    11461200    }
    11471201
     1202    /**
     1203     * Reload the image or reload only the image info. Call this if want to update the OSD.
     1204     * @param imageChanged reload the image if true. Reload only the OSD if false.
     1205     * @since 19387
     1206     */
     1207    public void refresh(boolean imageChanged) {
     1208        if (SwingUtilities.isEventDispatchThread()) {
     1209            this.updateButtonsNonNullEntry(currentEntry, imageChanged);
     1210        } else {
     1211            GuiHelper.runInEDT(this::refresh);
     1212        }
     1213    }
     1214   
    11481215    private void registerOnLayer(Layer layer) {
    11491216        if (layer instanceof IGeoImageLayer) {
  • trunk/src/org/openstreetmap/josm/gui/layer/geoimage/RemoteEntry.java

    r19050 r19387  
    3838    private Integer exifOrientation;
    3939    private Double elevation;
     40    private Integer gpsDiffMode;
     41    private Integer gps2d3dMode;
     42    private Double exifHPosErr;
     43    private Double exifGpsDop;
     44    private String exifGpsDatum;
     45    private String exifGpsProcMethod;
    4046    private Double speed;
    4147    private Double exifImgDir;
     48    private Double exifGpsTrack;
    4249    private ILatLon exifCoor;
    4350    private Instant exifTime;
     
    118125    }
    119126
     127    /**
     128     * @since 19387
     129     */
     130    @Override
     131    public void setGpsDiffMode(Integer gpsDiffMode) {
     132        this.gpsDiffMode = gpsDiffMode;
     133    }
     134
     135    /**
     136     * @since 19387
     137     */
     138    @Override
     139    public void setGps2d3dMode(Integer gps2d3dMode) {
     140        this.gps2d3dMode = gps2d3dMode;
     141    }
     142
     143    /**
     144     * @since 19387
     145     */
     146    @Override
     147    public void setExifGpsDatum(String exifGpsDatum) {
     148        this.exifGpsDatum = exifGpsDatum;
     149    }
     150
     151    /**
     152     * @since 19387
     153     */
     154    @Override
     155    public void setExifGpsProcMethod(String exifGpsProcMethod) {
     156        this.exifGpsProcMethod = exifGpsProcMethod;
     157    }
     158
    120159    @Override
    121160    public void setElevation(Double elevation) {
     
    153192    }
    154193
     194    /**
     195     * @since 19387
     196     */
     197    @Override
     198    public void setExifGpsTrack(Double exifGpsTrack) {
     199        this.exifGpsTrack = exifGpsTrack;
     200    }
     201
     202    /**
     203     * @since 19387
     204     */
     205    @Override
     206    public void setExifHPosErr(Double exifHPosError) {
     207        this.exifHPosErr = exifHPosError;
     208    }
     209
     210    /**
     211     * @since 19387
     212     */
     213    @Override
     214    public void setExifGpsDop(Double exifGpsDop) {
     215        this.exifGpsDop = exifGpsDop;
     216    }
     217
    155218    @Override
    156219    public void setIptcCaption(String iptcCaption) {
     
    213276    }
    214277
     278    /**
     279     * @since 19387
     280     */
     281    @Override
     282    public Integer getGpsDiffMode() {
     283        return this.gpsDiffMode;
     284    }
     285   
     286    /**
     287     * @since 19387
     288     */
     289    @Override
     290    public Integer getGps2d3dMode() {
     291        return this.gps2d3dMode;
     292    }
     293
     294    /**
     295     * @since 19387
     296     */
     297    @Override
     298    public String getExifGpsDatum() {
     299        return this.exifGpsDatum;
     300    }
     301
     302    /**
     303     * @since 19387
     304     */
     305    @Override
     306    public String getExifGpsProcMethod() {
     307        return this.exifGpsProcMethod;
     308    }
     309
     310    /**
     311     * @since 19387
     312     */
    215313    @Override
    216314    public Double getExifImgDir() {
    217315        return this.exifImgDir;
     316    }
     317
     318    /**
     319     * @since 19387
     320     */
     321    @Override
     322    public Double getExifGpsTrack() {
     323        return this.exifGpsTrack;
     324    }
     325
     326    /**
     327     * @since 19387
     328     */
     329    @Override
     330    public Double getExifHPosErr() {
     331        return this.exifHPosErr;
     332    }
     333
     334    /**
     335     * @since 19387
     336     */
     337    @Override
     338    public Double getExifGpsDop() {
     339        return this.exifGpsDop;
    218340    }
    219341
     
    336458        return Objects.hash(this.uri, this.pos,
    337459                this.exifOrientation, this.elevation, this.speed, this.exifImgDir,
    338                 this.exifCoor, this.exifTime, this.exifGpsTime, this.gpsTime,
    339                 this.iptcObjectName, this.iptcCaption, this.iptcHeadline, this.iptcKeywords,
    340                 this.projection, this.title);
     460                this.exifGpsTrack, this.exifCoor, this.exifTime, this.exifGpsTime,
     461                this.gpsTime, this.exifHPosErr, this.exifGpsDop, this.gpsDiffMode,
     462                this.gps2d3dMode, this.exifGpsDatum, this.exifGpsProcMethod,
     463                this.iptcObjectName, this.iptcCaption, this.iptcHeadline,
     464                this.iptcKeywords, this.projection, this.title);
    341465    }
    342466
     
    353477                    && Objects.equals(this.exifGpsTime, other.exifGpsTime)
    354478                    && Objects.equals(this.exifImgDir, other.exifImgDir)
     479                    && Objects.equals(this.exifGpsTrack, other.exifGpsTrack)
     480                    && Objects.equals(this.exifHPosErr, other.exifHPosErr)
     481                    && Objects.equals(this.exifGpsDop, other.exifGpsDop)
    355482                    && Objects.equals(this.exifOrientation, other.exifOrientation)
    356483                    && Objects.equals(this.exifTime, other.exifTime)
     
    363490                    && Objects.equals(this.projection, other.projection)
    364491                    && Objects.equals(this.speed, other.speed)
     492                    && Objects.equals(this.gpsDiffMode, other.gpsDiffMode)
     493                    && Objects.equals(this.gps2d3dMode, other.gps2d3dMode)
     494                    && Objects.equals(this.exifGpsDatum, other.exifGpsDatum)
     495                    && Objects.equals(this.exifGpsProcMethod, other.exifGpsProcMethod)
    365496                    && Objects.equals(this.title, other.title);
    366497        }
  • trunk/src/org/openstreetmap/josm/io/nmea/NmeaParser.java

    r19325 r19387  
    467467                    if (!accu.isEmpty() && currentwp != null) {
    468468                        Double.parseDouble(accu);
    469                         currentwp.put("course", accu);
     469                        currentwp.put(GpxConstants.PT_COURSE, accu);
    470470                    }
    471471                }
     
    543543                if (!accu.isEmpty() && !currentwp.attr.containsKey("course")) {
    544544                    Double.parseDouble(accu);
    545                     currentwp.put("course", accu);
     545                    currentwp.put(GpxConstants.PT_COURSE, accu);
    546546                }
    547547
  • trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionExporter.java

    r18069 r19387  
    2323 * Session exporter for {@link GeoImageLayer}.
    2424 * @since 5505
     25 * @since 19387 exifGpsTrack, exifHPosErr, gpsDiffMode, gps2d3dMode, exifGpsDop, exifGpsDatum, exifGpsProcMethod exporter added
    2526 */
    2627public class GeoImageSessionExporter extends AbstractSessionExporter<GeoImageLayer> {
     
    106107                addAttr("exif-image-direction", entry.getExifImgDir().toString(), imgElem, support);
    107108            }
     109            if (entry.getExifGpsTrack() != null) {
     110                addAttr("exif-gps-track", entry.getExifGpsTrack().toString(), imgElem, support);
     111            }
     112            if (entry.getExifHPosErr() != null) {
     113                addAttr("exif-gps-hposerr", entry.getExifHPosErr().toString(), imgElem, support);
     114            }
     115            if (entry.getGpsDiffMode() != null) {
     116                addAttr("exif-gps-diffmode", entry.getGpsDiffMode().toString(), imgElem, support);
     117            }
     118            if (entry.getGps2d3dMode() != null) {
     119                addAttr("exif-gps-2d3dmode", entry.getGps2d3dMode().toString(), imgElem, support);
     120            }
     121            if (entry.getExifGpsDop() != null) {
     122                addAttr("exif-gps-dop", entry.getExifGpsDop().toString(), imgElem, support);
     123            }
     124            if (entry.getExifGpsDatum() != null) {
     125                addAttr("exif-gps-datum", entry.getExifGpsDatum().toString(), imgElem, support);
     126            }
     127            if (entry.getExifGpsProcMethod() != null) {
     128                addAttr("exif-gps-procmethod", entry.getExifGpsProcMethod().toString(), imgElem, support);
     129            }
    108130            if (entry.hasNewGpsData()) {
    109131                addAttr("is-new-gps-data", Boolean.toString(entry.hasNewGpsData()), imgElem, support);
  • trunk/src/org/openstreetmap/josm/io/session/GeoImageSessionImporter.java

    r19050 r19387  
    2626 * Session importer for {@link GeoImageLayer}.
    2727 * @since 5505
     28 * @since 19387 exifGpsTrack, exifHPosErr, gpsDiffMode, gps2d3dMode, exifGpsDop, exifGpsDatum, exifGpsProcMethod importer added
    2829 */
    2930public class GeoImageSessionImporter implements SessionLayerImporter {
     
    109110                entry.setExifImgDir(Double.valueOf(attrElem.getTextContent()));
    110111                break;
     112            case "exif-gps-track":
     113                entry.setExifGpsTrack(Double.valueOf(attrElem.getTextContent()));
     114                break;
     115            case "exif-gps-hposerr":
     116                entry.setExifHPosErr(Double.valueOf(attrElem.getTextContent()));
     117                break;
     118            case "exif-gps-diffmode":
     119                entry.setGpsDiffMode(Integer.valueOf(attrElem.getTextContent()));
     120                break;
     121            case "exif-gps-2d3dmode":
     122                entry.setGps2d3dMode(Integer.valueOf(attrElem.getTextContent()));
     123                break;
     124            case "exif-gps-dop":
     125                entry.setExifGpsDop(Double.valueOf(attrElem.getTextContent()));
     126                break;
     127            case "exif-gps-datum":
     128                entry.setExifGpsDatum(attrElem.getTextContent());
     129                break;
     130            case "exif-gps-procmethod":
     131                entry.setExifGpsProcMethod(attrElem.getTextContent());
     132                break;
    111133            case "is-new-gps-data":
    112134                if (Boolean.parseBoolean(attrElem.getTextContent())) {
  • trunk/src/org/openstreetmap/josm/tools/ExifReader.java

    r19101 r19387  
    125125
    126126    /**
     127     * Returns the GPS date/time from the given JPEG file.
     128     * @param filename The JPEG file to read
     129     * @return The GPS date/time read in the EXIF section, or {@code null} if not found
     130     * @since 19387
     131     */
     132    public static Instant readGpsInstant(File filename) {
     133        try {
     134            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     135            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     136            return readGpsInstant(dirGps);
     137        } catch (JpegProcessingException | IOException e) {
     138            Logging.error(e);
     139        }
     140        return null;
     141    }
     142 
     143    /**
     144     * Returns the GPS date/time from the given JPEG file.
     145     * @param dirGps The EXIF GPS directory
     146     * @return The GPS date/time read in the EXIF section, or {@code null} if not found
     147     * @since 19387
     148     */
     149    public static Instant readGpsInstant(GpsDirectory dirGps) {
     150        if (dirGps != null) {
     151            try {
     152                Instant dateTimeStamp = dirGps.getGpsDate().toInstant();
     153                return dateTimeStamp;
     154            } catch (UncheckedParseException | DateTimeException e) {
     155                Logging.error(e);
     156            }
     157        }
     158        return null;
     159    }
     160 
     161    /**
    127162     * Returns the image orientation of the given JPEG file.
    128163     * @param filename The JPEG file to read
     
    219254    }
    220255
     256    /**
     257     * Returns the GPS track direction of the given JPEG file.
     258     * @param filename The JPEG file to read
     259     * @return The GPS track direction of the image when it was captures (in degrees between 0.0 and 359.99),
     260     * or {@code null} if not found
     261     * @since 19387
     262     */
     263    public static Double readGpsTrackDirection(File filename) {
     264        try {
     265            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     266            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     267            return readGpsTrackDirection(dirGps);
     268        } catch (JpegProcessingException | IOException e) {
     269            Logging.error(e);
     270        }
     271        return null;
     272    }
     273   
     274    /**
     275     * Returns the GPS track direction of the given EXIF GPS directory.
     276     * @param dirGps The EXIF GPS directory
     277     * @return The GPS track direction of the image when it was captured (in degrees between 0.0 and 359.99),
     278     * or {@code null} if missing or if {@code dirGps} is null
     279     * @since 19387
     280     */
     281    public static Double readGpsTrackDirection(GpsDirectory dirGps) {
     282        if (dirGps != null) {
     283            Rational trackDirection = dirGps.getRational(GpsDirectory.TAG_TRACK);
     284            if (trackDirection != null) {
     285                return trackDirection.doubleValue();
     286            }
     287        }
     288        return null;
     289    }
     290
    221291    private static double readAxis(GpsDirectory dirGps, int gpsTag, int gpsTagRef, char cRef) throws MetadataException {
    222292        double value;
     
    319389                }
    320390                return ele;
     391            }
     392        }
     393        return null;
     394    }
     395
     396    /**
     397     * Returns the GPS horizontal positionning error of the given JPEG file.
     398     * @param filename The JPEG file to read
     399     * @return The GPS horizontal positionning error of the camera when the image was captured (in m),
     400     *         or {@code null} if not found
     401     * @since 19387
     402     */
     403    public static Double readHpositioningError(File filename) {
     404        try {
     405            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     406            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     407            return readHpositioningError(dirGps);
     408        } catch (JpegProcessingException | IOException e) {
     409            Logging.error(e);
     410        }
     411        return null;
     412    }
     413
     414    /**
     415     * Returns the GPS horizontal positionning error of the given EXIF GPS directory.
     416     * @param dirGps The EXIF GPS directory
     417     * @return The GPS horizontal positionning error of the camera when the image was captured (in m),
     418     *         or {@code null} if missing or if {@code dirGps} is null
     419     * @since 19387
     420     */
     421    public static Double readHpositioningError(GpsDirectory dirGps) {
     422        if (dirGps != null) {
     423            Double hposerr = dirGps.getDoubleObject(GpsDirectory.TAG_H_POSITIONING_ERROR);
     424            if (hposerr != null) {
     425                return hposerr.doubleValue();
     426            }
     427        }
     428        return null;
     429    }
     430
     431    /**
     432     * Returns the GPS differential mode of the given JPEG file.
     433     * @param filename The JPEG file to read
     434     * @return The GPS differential mode of the camera when the image was captured,
     435     * <ul>
     436     *  <li>0 : no differential correction</li>
     437     *  <li>1 : differential correction</li>
     438     *  <li>or {@code null} if not found</li>
     439     * </ul>
     440     * @since 19387
     441     */
     442    public static Integer readGpsDiffMode(File filename) {
     443        try {
     444            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     445            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     446            return readGpsDiffMode(dirGps);
     447        } catch (JpegProcessingException | IOException e) {
     448            Logging.error(e);
     449        }
     450        return null;
     451    }
     452
     453    /**
     454     * Returns the GPS differential mode of the given EXIF GPS directory.
     455     * @param dirGps The EXIF GPS directory
     456     * @return The GPS differential mode of the camera when the image was captured,
     457     * <ul>
     458     *  <li>0 : no differential correction</li>
     459     *  <li>1 : differential correction</li>
     460     *  <li>or {@code null} if missing or if {@code dirGps} is null</li>
     461     * </ul>
     462     * @since 19387
     463     */   
     464    public static Integer readGpsDiffMode(GpsDirectory dirGps) {
     465        if (dirGps != null) {
     466            Integer gpsDiffMode = dirGps.getInteger(GpsDirectory.TAG_DIFFERENTIAL);
     467            if (gpsDiffMode != null) {
     468                return gpsDiffMode.intValue();
     469            }
     470        }
     471        return null;
     472    }
     473
     474    /**
     475     * Returns the GPS 2d/3d mode of the given JPEG file.
     476     * @param filename The JPEG file to read
     477     * @return The GPS 2d/3d mode of the camera when the image was captured,
     478     * <ul>
     479     *  <li>2 : 2d mode</li>
     480     *  <li>2 : 3d mode</li>
     481     *  <li>or {@code null} if not found</li>
     482     * </ul>
     483     * @since 19387
     484     */
     485    public static Integer readGpsMeasureMode(File filename) {
     486        try {
     487            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     488            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     489            return readGpsMeasureMode(dirGps);
     490        } catch (JpegProcessingException | IOException e) {
     491            Logging.error(e);
     492        }
     493        return null;
     494    }
     495
     496    /**
     497     * Returns the GPS 2d/3d mode of the given EXIF GPS directory.
     498     * @param dirGps The EXIF GPS directory
     499     * @return The 2d/3d mode of the camera when the image was captured,
     500     * <ul>
     501     *  <li>2 : 2d mode</li>
     502     *  <li>3 : 3d mode</li>
     503     *  <li>or {@code null} if missing or if {@code dirGps} is null</li>
     504     * </ul>
     505     * @since 19387
     506     */   
     507    public static Integer readGpsMeasureMode(GpsDirectory dirGps) {
     508        if (dirGps != null) {
     509            Integer gps2d3dMode = dirGps.getInteger(GpsDirectory.TAG_MEASURE_MODE);
     510            if (gps2d3dMode != null) {
     511                return gps2d3dMode.intValue();
     512            }
     513        }
     514        return null;
     515    }
     516
     517    /**
     518     * Returns the GPS DOP value of the given JPEG file.
     519     * @param filename The JPEG file to read
     520     * @return The GPS DOP value of the camera when the image was captured,
     521     *         or {@code null} if not found
     522     * @since 19387
     523     */
     524    public static Double readGpsDop(File filename) {
     525        try {
     526            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     527            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     528            return readGpsDop(dirGps);
     529        } catch (JpegProcessingException | IOException e) {
     530            Logging.error(e);
     531        }
     532        return null;
     533    }
     534
     535    /**
     536     * Returns the GPS DOP value of the given EXIF GPS directory.
     537     * @param dirGps The EXIF GPS directory
     538     * @return The GPS DOP value of the camera when the image was captured,
     539     *         or {@code null} if missing or if {@code dirGps} is null
     540     * @since 19387
     541     */
     542    public static Double readGpsDop(GpsDirectory dirGps) {
     543        if (dirGps != null) {
     544            Double gpsDop = dirGps.getDoubleObject(GpsDirectory.TAG_DOP);
     545            if (gpsDop != null) {
     546                return gpsDop.doubleValue();
     547            }
     548        }
     549        return null;
     550    }
     551
     552    /**
     553     * Returns the GPS datum value of the given JPEG file.
     554     * @param filename The JPEG file to read
     555     * @return The GPS datum value of the camera when the image was captured,
     556     *         or {@code null} if not found
     557     * @since 19387
     558     */
     559    public static String readGpsDatum(File filename) {
     560        try {
     561            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     562            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     563            return readGpsDatum(dirGps);
     564        } catch (JpegProcessingException | IOException e) {
     565            Logging.error(e);
     566        }
     567        return null;
     568    }
     569
     570    /**
     571     * Returns the GPS datum value of the given EXIF GPS directory.
     572     * @param dirGps The EXIF GPS directory
     573     * @return The GPS datum value of the camera when the image was captured,
     574     *         or {@code null} if missing or if {@code dirGps} is null
     575     * @since 19387
     576     */
     577    public static String readGpsDatum(GpsDirectory dirGps) {
     578        if (dirGps != null) {
     579            String gpsDatum = dirGps.getString(GpsDirectory.TAG_MAP_DATUM);
     580            if (gpsDatum != null) {
     581                return gpsDatum.toString();
     582            }
     583        }
     584        return null;
     585    }
     586
     587    /**
     588     * Return the GPS processing method of the given JPEG file.
     589     * @param filename The JPEG file to read
     590     * @return The GPS processing method. Possible values from the EXIF specs are:
     591     * <ul>
     592     * <li>GPS</li>
     593     * <li>QZSS</li>
     594     * <li>GALILEO</li>
     595     * <li>GLONASS</li>
     596     * <li>BEIDOU</li>
     597     * <li>NAVIC</li>
     598     * <li>CELLID</li>
     599     * <li>WLAN</li>
     600     * <li>MANUAL</li>
     601     * </ul>
     602     * Other values, and combined space separated values are possible too.
     603     * or {@code null} if missing
     604     * @since 19387
     605     */
     606    public static String readGpsProcessingMethod(File filename) {
     607        try {
     608            final Metadata metadata = JpegMetadataReader.readMetadata(filename);
     609            final GpsDirectory dirGps = metadata.getFirstDirectoryOfType(GpsDirectory.class);
     610            return readGpsProcessingMethod(dirGps);
     611        } catch (JpegProcessingException | IOException e) {
     612            Logging.error(e);
     613        }
     614        return null;
     615    }
     616
     617    /**
     618     * Return the GPS processing method of the given EXIF GPS directory.
     619     * @param dirGps The EXIF GPS directory
     620     * @return The GPS processing method. Possible values from the EXIF specs are:
     621     * <ul>
     622     * <li>GPS</li>
     623     * <li>QZSS</li>
     624     * <li>GALILEO</li>
     625     * <li>GLONASS</li>
     626     * <li>BEIDOU</li>
     627     * <li>NAVIC</li>
     628     * <li>CELLID</li>
     629     * <li>WLAN</li>
     630     * <li>MANUAL</li>
     631     * </ul>
     632     * Other values, and combined space separated values are possible too.
     633     * or {@code null} if missing or if {@code dirGps} is null
     634     * @since 19387
     635     */
     636    public static String readGpsProcessingMethod(GpsDirectory dirGps) {
     637        if (dirGps != null) {
     638            String gpsProcessingMethod = dirGps.getDescription(GpsDirectory.TAG_PROCESSING_METHOD);
     639            if (gpsProcessingMethod != null) {
     640                return gpsProcessingMethod.toString();
    321641            }
    322642        }
  • trunk/test/unit/org/openstreetmap/josm/data/ImageDataTest.java

    r18444 r19387  
    446446
    447447    @Test
     448    void testUpdateHPosErr() {
     449        List<ImageEntry> list = getOneImage();
     450        ImageData data = new ImageData(list);
     451
     452        new Expectations(list.get(0)) {{
     453            list.get(0).setExifHPosErr(1.23);
     454            list.get(0).flagNewGpsData();
     455        }};
     456        data.updateImageHPosErr(list.get(0), 1.23);
     457    }
     458
     459    @Test
     460    void testUpdateGpsDatum() {
     461        List<ImageEntry> list = getOneImage();
     462        ImageData data = new ImageData(list);
     463
     464        new Expectations(list.get(0)) {{
     465            list.get(0).setExifGpsDatum("WGS-84");
     466            list.get(0).flagNewGpsData();
     467        }};
     468        data.updateImageExifGpsDatum(list.get(0), "WGS-84");
     469    }
     470
     471    @Test
     472    void testUpdateGpsTrack() {
     473        List<ImageEntry> list = getOneImage();
     474        ImageData data = new ImageData(list);
     475
     476        new Expectations(list.get(0)) {{
     477            list.get(0).setExifGpsTrack(180.5);
     478            list.get(0).flagNewGpsData();
     479        }};
     480        data.updateImageGpsTrack(list.get(0), 180.5);
     481    }
     482
     483    @Test
     484    void testUpdateGpsDop() {
     485        List<ImageEntry> list = getOneImage();
     486        ImageData data = new ImageData(list);
     487
     488        new Expectations(list.get(0)) {{
     489            list.get(0).setExifGpsDop(1.9);
     490            list.get(0).flagNewGpsData();
     491        }};
     492        data.updateImageExifGpsDop(list.get(0), 1.9);
     493    }
     494
     495    @Test
     496    void testUpdateGpsProcMethod() {
     497        List<ImageEntry> list = getOneImage();
     498        ImageData data = new ImageData(list);
     499
     500        new Expectations(list.get(0)) {{
     501            list.get(0).setExifGpsProcMethod("GNSS RTK CORRELATION");
     502            list.get(0).flagNewGpsData();
     503        }};
     504        data.updateImageExifGpsProcMethod(list.get(0), "GNSS RTK CORRELATION");
     505    }
     506
     507    @Test
     508    void testUpdateGpsDifferentialMode() {
     509        List<ImageEntry> list = getOneImage();
     510        ImageData data = new ImageData(list);
     511
     512        new Expectations(list.get(0)) {{
     513            list.get(0).setGpsDiffMode(1);
     514            list.get(0).flagNewGpsData();
     515        }};
     516        data.updateImageGpsDiffMode(list.get(0), 1);
     517    }
     518
     519    @Test
     520    void testUpdateGps2d3dMode() {
     521        List<ImageEntry> list = getOneImage();
     522        ImageData data = new ImageData(list);
     523
     524        new Expectations(list.get(0)) {{
     525            list.get(0).setGps2d3dMode(3);
     526            list.get(0).flagNewGpsData();
     527        }};
     528        data.updateImageGps2d3dMode(list.get(0), 3);
     529    }
     530
     531    @Test
    448532    void testTriggerListenerOnUpdate() {
    449533        List<ImageEntry> list = getOneImage();
  • trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxImageCorrelationTest.java

    r18853 r19387  
    351351        assertEquals(Double.valueOf(150.0d), GpxImageCorrelation.getElevation(wp));
    352352    }
     353
     354    /**
     355     * Unit test of {@link GpxImageCorrelation#getHPosErr}
     356     */
     357    @Test
     358    void testGetHorizontalPosError() {
     359        assertNull(GpxImageCorrelation.getHPosErr(null));
     360        WayPoint wp = new WayPoint(LatLon.ZERO);
     361        assertNull(GpxImageCorrelation.getHPosErr(wp));
     362        wp.put(GpxConstants.PT_STD_HDEV, 1.5f);
     363        assertEquals(1.5f, GpxImageCorrelation.getHPosErr(wp));
     364    }
     365
     366    /**
     367     * Unit test of {@link GpxImageCorrelation#getGpsDop}
     368     */
     369    @Test
     370    void testGetGpsDop() {
     371        assertNull(GpxImageCorrelation.getGpsDop(null));
     372        WayPoint wp = new WayPoint(LatLon.ZERO);
     373        assertNull(GpxImageCorrelation.getGpsDop(wp));
     374        wp.put(GpxConstants.PT_HDOP, 2.1f);
     375        assertEquals(2.1f, GpxImageCorrelation.getGpsDop(wp));
     376        wp.put(GpxConstants.PT_PDOP, 0.9f);
     377        assertEquals(0.9f, GpxImageCorrelation.getGpsDop(wp));
     378        wp.put(GpxConstants.PT_PDOP, 1.2d);
     379        assertEquals(1.2d, GpxImageCorrelation.getGpsDop(wp));
     380    }
     381
     382    /**
     383     * Unit test of {@link GpxImageCorrelation#getGpsTrack}
     384     */
     385    @Test
     386    void testGetGpsTrack() {
     387        assertNull(GpxImageCorrelation.getHPosErr(null));
     388        WayPoint wp = new WayPoint(LatLon.ZERO);
     389        assertNull(GpxImageCorrelation.getGpsTrack(wp));
     390        wp.put(GpxConstants.PT_COURSE, "");
     391        assertNull(GpxImageCorrelation.getGpsTrack(wp));
     392        wp.put(GpxConstants.PT_COURSE, "not a number");
     393        assertNull(GpxImageCorrelation.getGpsTrack(wp));
     394        wp.put(GpxConstants.PT_COURSE, "167.0");
     395        assertEquals(Double.valueOf(167.0d), GpxImageCorrelation.getGpsTrack(wp), 0.01d);
     396    }
     397
     398    /**
     399     * Unit test of {@link GpxImageCorrelation#getGpsProcMethod}
     400     */
     401    @Test
     402    void testGetGpsProcMethod() {
     403        final List<String> positionningModes = Arrays.asList("none", "manual", "estimated", "2d", "3d", "dgps", "float rtk", "rtk");
     404        assertNull(GpxImageCorrelation.getGpsProcMethod(null, null, positionningModes));
     405        assertNull(GpxImageCorrelation.getGpsProcMethod("", "", positionningModes));
     406        assertNull(GpxImageCorrelation.getGpsProcMethod("3d", null, positionningModes));
     407        assertNull(GpxImageCorrelation.getGpsProcMethod("", "dgps", positionningModes));
     408        assertEquals("MANUAL CORRELATION", GpxImageCorrelation.getGpsProcMethod("manual", "rtk", positionningModes));
     409        assertEquals("ESTIMATED CORRELATION", GpxImageCorrelation.getGpsProcMethod("estimated", "2d", positionningModes));
     410        assertEquals("GNSS DGPS CORRELATION", GpxImageCorrelation.getGpsProcMethod("rtk", "dgps", positionningModes));
     411        assertEquals("GNSS RTK_FLOAT CORRELATION", GpxImageCorrelation.getGpsProcMethod("float rtk", "rtk", positionningModes));
     412        assertEquals("GNSS RTK_FIX CORRELATION", GpxImageCorrelation.getGpsProcMethod("rtk", "rtk", positionningModes));
     413    }
     414
     415    /**
     416     * Unit test of {@link GpxImageCorrelation#getGps2d3dMode}
     417     */
     418    @Test
     419    void testGetGps2d3dMode() {
     420        final List<String> positionningModes = Arrays.asList("none", "manual", "estimated", "2d", "3d", "dgps", "float rtk", "rtk");
     421        assertNull(GpxImageCorrelation.getGps2d3dMode(null, null, positionningModes));
     422        assertNull(GpxImageCorrelation.getGps2d3dMode("", "", positionningModes));
     423        assertNull(GpxImageCorrelation.getGps2d3dMode("3d", null, positionningModes));
     424        assertNull(GpxImageCorrelation.getGps2d3dMode("", "dgps", positionningModes));
     425        assertNull(GpxImageCorrelation.getGps2d3dMode("estimated", "rtk", positionningModes));
     426        assertEquals(2, GpxImageCorrelation.getGps2d3dMode("2d", "2d", positionningModes));
     427        assertEquals(2, GpxImageCorrelation.getGps2d3dMode("2d", "3d", positionningModes));
     428        assertEquals(3, GpxImageCorrelation.getGps2d3dMode("3d", "dgps", positionningModes));
     429    }
    353430}
  • trunk/test/unit/org/openstreetmap/josm/tools/ExifReaderTest.java

    r18853 r19387  
    2222 */
    2323class ExifReaderTest {
    24     private File orientationSampleFile, directionSampleFile;
     24    private File orientationSampleFile, directionSampleFile, positionErrorSampleFile;
    2525
    2626    /**
     
    3131        directionSampleFile = new File("nodist/data/exif-example_direction.jpg");
    3232        orientationSampleFile = new File("nodist/data/exif-example_orientation=6.jpg");
     33        positionErrorSampleFile = new File("nodist/data/exif-position-error.jpg");
    3334    }
    3435
     
    5657    }
    5758
     59    /**
     60     * Test reading GPS date and time
     61     */
     62    @Test
     63    void testReadGpsDateTime() {
     64        Instant date = ExifReader.readGpsInstant(positionErrorSampleFile);
     65        assertEquals(Instant.parse("2024-04-30T16:36:42Z"), date);
     66    }
     67 
    5868    /**
    5969     * Test orientation extraction
     
    102112
    103113    /**
     114     * Test horizontal position error extraction
     115     */
     116    @Test
     117    void testReadHorPosError() {
     118        assertEquals(Double.valueOf(0.014), ExifReader.readHpositioningError(positionErrorSampleFile));
     119    }
     120
     121    /**
     122     * Test GPS track course extraction
     123     */
     124    @Test
     125    void testReadGpsTrack() {
     126        assertEquals(Double.valueOf(298), ExifReader.readGpsTrackDirection(positionErrorSampleFile));
     127    }
     128
     129    /**
     130     * Test GPS differential mode extraction
     131     */
     132    @Test
     133    void testReadGpsDiffmode() {
     134        assertEquals(Integer.valueOf(1), ExifReader.readGpsDiffMode(positionErrorSampleFile));
     135    }
     136
     137    /**
     138     * Test GPS DOP value extraction
     139     */
     140    @Test
     141    void testReadGpsDop() {
     142        assertEquals(Double.valueOf(0.92), ExifReader.readGpsDop(positionErrorSampleFile));
     143    }
     144
     145    /**
     146     * Test GPS measure mode (2D/3D) extraction
     147     */
     148    @Test
     149    void testReadGps2d3dMode() {
     150        assertEquals(Integer.valueOf(3), ExifReader.readGpsMeasureMode(positionErrorSampleFile));
     151    }
     152
     153    /**
     154     * Test GPS datum extraction
     155     */
     156    @Test
     157    void testReadGpsDatum() {
     158        assertEquals(String.valueOf("EPSG:9782"), ExifReader.readGpsDatum(positionErrorSampleFile));
     159    }
     160
     161    /**
     162     * Test GPS processing method extraction
     163     */
     164    @Test
     165    void testReadGpsProcMethod() {
     166        assertEquals(String.valueOf("GNSS RTK_FIX CORRELATION"), ExifReader.readGpsProcessingMethod(positionErrorSampleFile));
     167    }
     168
     169    /**
    104170     * Non-regression test for ticket <a href="https://josm.openstreetmap.de/ticket/11685">#11685</a>
    105171     * @throws IOException if an error occurs during reading
Note: See TracChangeset for help on using the changeset viewer.