Changeset 18207 in josm for trunk


Ignore:
Timestamp:
2021-09-11T17:00:13+02:00 (3 years ago)
Author:
Don-vip
Message:

fix #21257 - sort tracks chronologically when writing GPX file

Location:
trunk
Files:
4 edited

Legend:

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

    r17845 r18207  
    1919import java.util.Objects;
    2020import java.util.Optional;
     21import java.util.OptionalLong;
    2122import java.util.Set;
    2223import java.util.stream.Collectors;
     
    3334import org.openstreetmap.josm.tools.ListenerList;
    3435import org.openstreetmap.josm.tools.ListeningCollection;
     36import org.openstreetmap.josm.tools.Utils;
    3537import org.openstreetmap.josm.tools.date.Interval;
    3638
     
    386388
    387389    /**
    388      * Get all tracks contained in this data set.
     390     * Get all tracks contained in this data set, without any guaranteed order.
    389391     * @return The tracks.
    390392     */
    391393    public synchronized Collection<IGpxTrack> getTracks() {
    392394        return Collections.unmodifiableCollection(privateTracks);
     395    }
     396
     397    /**
     398     * Get all tracks contained in this data set, ordered chronologically.
     399     * @return The tracks in chronological order.
     400     * @since 18207
     401     */
     402    public synchronized List<IGpxTrack> getOrderedTracks() {
     403        return privateTracks.stream().sorted((t1, t2) -> {
     404            boolean t1empty = Utils.isEmpty(t1.getSegments());
     405            boolean t2empty = Utils.isEmpty(t2.getSegments());
     406            if (t1empty && t2empty) {
     407                return 0;
     408            } else if (t1empty && !t2empty) {
     409                return -1;
     410            } else if (!t1empty && t2empty) {
     411                return 1;
     412            } else {
     413                OptionalLong i1 = getTrackFirstWaypointMin(t1);
     414                OptionalLong i2 = getTrackFirstWaypointMin(t2);
     415                boolean i1absent = !i1.isPresent();
     416                boolean i2absent = !i2.isPresent();
     417                if (i1absent && i2absent) {
     418                    return 0;
     419                } else if (i1absent && !i2absent) {
     420                    return 1;
     421                } else if (!i1absent && i2absent) {
     422                    return -1;
     423                } else {
     424                    return Long.compare(i1.getAsLong(), i2.getAsLong());
     425                }
     426            }
     427        }).collect(Collectors.toList());
     428    }
     429
     430    private static OptionalLong getTrackFirstWaypointMin(IGpxTrack track) {
     431        return track.getSegments().stream().map(IGpxTrackSegment::getWayPoints)
     432                .filter(Objects::nonNull).flatMap(Collection::stream)
     433                .mapToLong(WayPoint::getTimeInMillis).min();
    393434    }
    394435
  • trunk/src/org/openstreetmap/josm/io/GpxWriter.java

    r18206 r18207  
    266266
    267267    private void writeTracks() {
    268         for (IGpxTrack trk : data.getTracks()) {
     268        for (IGpxTrack trk : data.getOrderedTracks()) {
    269269            openln("trk");
    270270            writeAttr(trk, RTE_TRK_KEYS);
  • trunk/src/org/openstreetmap/josm/tools/Utils.java

    r18072 r18207  
    650650    public static <T> List<T> toUnmodifiableList(Collection<T> collection) {
    651651        // Java 9: use List.of(...)
    652         if (collection == null || collection.isEmpty()) {
     652        if (isEmpty(collection)) {
    653653            return Collections.emptyList();
    654654        } else if (collection.size() == 1) {
     
    672672    @SuppressWarnings("unchecked")
    673673    public static <K, V> Map<K, V> toUnmodifiableMap(Map<K, V> map) {
    674         if (map == null || map.isEmpty()) {
     674        if (isEmpty(map)) {
    675675            return Collections.emptyMap();
    676676        } else if (map.size() == 1) {
     
    689689
    690690    /**
     691     * Determines if a collection is null or empty.
     692     * @param collection collection
     693     * @return {@code true} if collection is null or empty
     694     * @since 18207
     695     */
     696    public static boolean isEmpty(Collection<?> collection) {
     697        return collection == null || collection.isEmpty();
     698    }
     699
     700    /**
     701     * Determines if a map is null or empty.
     702     * @param map map
     703     * @return {@code true} if map is null or empty
     704     * @since 18207
     705     */
     706    public static boolean isEmpty(Map<?, ?> map) {
     707        return map == null || map.isEmpty();
     708    }
     709
     710    /**
     711     * Determines if a string is null or empty.
     712     * @param string string
     713     * @return {@code true} if string is null or empty
     714     * @since 18207
     715     */
     716    public static boolean isEmpty(String string) {
     717        return string == null || string.isEmpty();
     718    }
     719
     720    /**
    691721     * Returns the first not empty string in the given candidates, otherwise the default string.
    692722     * @param defaultString default string returned if all candidates would be empty if stripped
     
    737767     */
    738768    public static String strip(final String str, final String skipChars) {
    739         if (str == null || str.isEmpty()) {
     769        if (isEmpty(str)) {
    740770            return str;
    741771        }
     
    774804     */
    775805    public static String removeWhiteSpaces(String s) {
    776         if (s == null || s.isEmpty()) {
     806        if (isEmpty(s)) {
    777807            return s;
    778808        }
  • trunk/test/unit/org/openstreetmap/josm/data/gpx/GpxDataTest.java

    r17845 r18207  
    323323        data.addTrack(track2);
    324324        assertEquals(3 * new LatLon(0, 0).greatCircleDistance(new LatLon(1, 1)), data.length(), 1);
    325 
     325    }
     326
     327    /**
     328     * Test method for {@link GpxData#getOrderedTracks()}.
     329     */
     330    @Test
     331    void testGetOrderedTracks() {
     332        assertTrue(data.getOrderedTracks().isEmpty());
     333
     334        WayPoint p1 = new WayPoint(LatLon.NORTH_POLE);
     335        WayPoint p2 = new WayPoint(LatLon.NORTH_POLE);
     336
     337        p1.setInstant(Instant.ofEpochMilli(100020));
     338        p2.setInstant(Instant.ofEpochMilli(200020));
     339
     340        data.addTrack(new GpxTrack(Arrays.asList(Arrays.asList(p2)), Collections.emptyMap()));
     341        data.addTrack(new GpxTrack(Arrays.asList(Arrays.asList(p1)), Collections.emptyMap()));
     342
     343        List<IGpxTrack> tracks = data.getOrderedTracks();
     344        assertEquals(2, tracks.size());
     345
     346        assertEquals(p1, tracks.get(0).getSegments().iterator().next().getWayPoints().iterator().next());
     347        assertEquals(p2, tracks.get(1).getSegments().iterator().next().getWayPoints().iterator().next());
    326348    }
    327349
Note: See TracChangeset for help on using the changeset viewer.