Ignore:
Timestamp:
2017-12-17T15:37:11+01:00 (2 years ago)
Author:
Don-vip
Message:

fix #15606 - export relation to GPX file or convert to a new GPX layer (patch by cmuelle8, modified)

Location:
trunk/src/org/openstreetmap/josm/data/gpx
Files:
3 edited

Legend:

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

    r13136 r13210  
    55import java.text.MessageFormat;
    66import java.util.ArrayList;
     7import java.util.Arrays;
    78import java.util.Collection;
    89import java.util.Collections;
    910import java.util.Date;
    1011import java.util.DoubleSummaryStatistics;
     12import java.util.HashMap;
    1113import java.util.HashSet;
    1214import java.util.Iterator;
     15import java.util.List;
    1316import java.util.Map;
    1417import java.util.NoSuchElementException;
    1518import java.util.Set;
     19import java.util.stream.Collectors;
    1620import java.util.stream.Stream;
    1721
     
    2226import org.openstreetmap.josm.data.coor.EastNorth;
    2327import org.openstreetmap.josm.data.gpx.GpxTrack.GpxTrackChangeListener;
     28import org.openstreetmap.josm.gui.MainApplication;
     29import org.openstreetmap.josm.gui.layer.GpxLayer;
    2430import org.openstreetmap.josm.tools.ListenerList;
    2531import org.openstreetmap.josm.tools.ListeningCollection;
     
    141147
    142148    /**
     149     * Get Stream<> of track segments as introduced in Java 8.
     150     * @return {@code Stream<GPXTrack>}
     151     */
     152    private synchronized Stream<GpxTrackSegment> getTrackSegmentsStream() {
     153        return getTracks().stream().flatMap(trk -> trk.getSegments().stream());
     154    }
     155
     156    /**
     157     * Clear all tracks, empties the current privateTracks container,
     158     * helper method for some gpx manipulations.
     159     */
     160    private synchronized void clearTracks() {
     161        privateTracks.forEach(t -> t.removeListener(proxy));
     162        privateTracks.clear();
     163    }
     164
     165    /**
    143166     * Add a new track
    144167     * @param track The new track
     
    165188        track.removeListener(proxy);
    166189        fireInvalidate();
     190    }
     191
     192    /**
     193     * Combine tracks into a single, segmented track.
     194     * The attributes of the first track are used, the rest discarded.
     195     *
     196     * @since 13210
     197     */
     198    public synchronized void combineTracksToSegmentedTrack() {
     199        List<GpxTrackSegment> segs = getTrackSegmentsStream()
     200                .collect(Collectors.toCollection(ArrayList<GpxTrackSegment>::new));
     201        Map<String, Object> attrs = new HashMap<>(privateTracks.get(0).getAttributes());
     202
     203        // do not let the name grow if split / combine operations are called iteratively
     204        attrs.put("name", attrs.get("name").toString().replaceFirst(" #\\d+$", ""));
     205
     206        clearTracks();
     207        addTrack(new ImmutableGpxTrack(segs, attrs));
     208    }
     209
     210    /**
     211     * @param attrs attributes of/for an gpx track, written to if the name appeared previously in {@code counts}.
     212     * @param counts a {@code HashMap} of previously seen names, associated with their count.
     213     * @return the unique name for the gpx track.
     214     *
     215     * @since 13210
     216     */
     217    public static String ensureUniqueName(Map<String, Object> attrs, Map<String, Integer> counts) {
     218        String name = attrs.getOrDefault("name", "GPX split result").toString();
     219        Integer count = counts.getOrDefault(name, 0) + 1;
     220        counts.put(name, count);
     221
     222        attrs.put("name", MessageFormat.format("{0}{1}", name, (count > 1) ? " #"+count : ""));
     223        return attrs.get("name").toString();
     224    }
     225
     226    /**
     227     * Split tracks so that only single-segment tracks remain.
     228     * Each segment will make up one individual track after this operation.
     229     *
     230     * @since 13210
     231     */
     232    public synchronized void splitTrackSegmentsToTracks() {
     233        final HashMap<String, Integer> counts = new HashMap<>();
     234
     235        List<GpxTrack> trks = getTracks().stream()
     236            .flatMap(trk -> {
     237                return trk.getSegments().stream().map(seg -> {
     238                    HashMap<String, Object> attrs = new HashMap<>(trk.getAttributes());
     239                    ensureUniqueName(attrs, counts);
     240                    return new ImmutableGpxTrack(Arrays.asList(seg), attrs);
     241                });
     242            })
     243            .collect(Collectors.toCollection(ArrayList<GpxTrack>::new));
     244
     245        clearTracks();
     246        trks.stream().forEachOrdered(trk -> addTrack(trk));
     247    }
     248
     249    /**
     250     * Split tracks into layers, the result is one layer for each track.
     251     * If this layer currently has only one GpxTrack this is a no-operation.
     252     *
     253     * The new GpxLayers are added to the LayerManager, the original GpxLayer
     254     * is untouched as to preserve potential route or wpt parts.
     255     *
     256     * @since 13210
     257     */
     258    public synchronized void splitTracksToLayers() {
     259        final HashMap<String, Integer> counts = new HashMap<>();
     260
     261        getTracks().stream()
     262            .filter(trk -> privateTracks.size() > 1)
     263            .map(trk -> {
     264                HashMap<String, Object> attrs = new HashMap<>(trk.getAttributes());
     265                GpxData d = new GpxData();
     266                d.addTrack(trk);
     267                return new GpxLayer(d, ensureUniqueName(attrs, counts)); })
     268            .forEachOrdered(layer -> MainApplication.getLayerManager().addLayer(layer));
     269    }
     270
     271    /**
     272     * Replies the current number of tracks in this GpxData
     273     * @return track count
     274     * @since 13210
     275     */
     276    public synchronized int getTrackCount() {
     277        return privateTracks.size();
     278    }
     279
     280    /**
     281     * Replies the accumulated total of all track segments,
     282     * the sum of segment counts for each track present.
     283     * @return track segments count
     284     * @since 13210
     285     */
     286    public synchronized int getTrackSegsCount() {
     287        return privateTracks.stream().collect(Collectors.summingInt(t -> t.getSegments().size()));
    167288    }
    168289
  • trunk/src/org/openstreetmap/josm/data/gpx/ImmutableGpxTrack.java

    r12289 r13210  
    3535        this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));
    3636        this.segments = Collections.unmodifiableList(newSegments);
     37        this.length = calculateLength();
     38        this.bounds = calculateBounds();
     39    }
     40
     41    /**
     42     * Constructs a new {@code ImmutableGpxTrack} from {@code GpxTrackSegment} objects.
     43     * @param segments The segments to build the track from.  Input is not deep-copied,
     44     *                 which means the caller may reuse the same segments to build
     45     *                 multiple ImmutableGpxTrack instances from.  This should not be
     46     *                 a problem, since this object cannot modify {@code this.segments}.
     47     * @param attributes Attributes for the GpxTrack, the input map is copied.
     48     * @since 13210
     49     */
     50    public ImmutableGpxTrack(List<GpxTrackSegment> segments, Map<String, Object> attributes) {
     51        this.attr = Collections.unmodifiableMap(new HashMap<>(attributes));
     52        this.segments = Collections.unmodifiableList(segments);
    3753        this.length = calculateLength();
    3854        this.bounds = calculateBounds();
  • trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java

    r12656 r13210  
    143143    public void setTime() {
    144144        setTimeFromAttribute();
     145    }
     146
     147    /**
     148     * Set the the time stamp of the waypoint into seconds from the epoch,
     149     * @param time millisecond from the epoch
     150     * @since 13210
     151     */
     152    public void setTime(long time) {
     153        this.time = time / 1000.;
    145154    }
    146155
Note: See TracChangeset for help on using the changeset viewer.