source: josm/trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java @ 14434

Last change on this file since 14434 was 14434, checked in by Don-vip, 3 months ago

fix #16995 - fix timestamp in GPX exports (patch by cmuelle8) + use Java 8 unsigned int API

  • Property svn:eol-style set to native
File size: 7.3 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.gpx;
3
4import java.awt.Color;
5import java.time.DateTimeException;
6import java.util.ArrayList;
7import java.util.Date;
8import java.util.List;
9import java.util.Objects;
10
11import org.openstreetmap.josm.data.coor.EastNorth;
12import org.openstreetmap.josm.data.coor.ILatLon;
13import org.openstreetmap.josm.data.coor.LatLon;
14import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
15import org.openstreetmap.josm.data.projection.Projecting;
16import org.openstreetmap.josm.tools.Logging;
17import org.openstreetmap.josm.tools.UncheckedParseException;
18import org.openstreetmap.josm.tools.date.DateUtils;
19import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
20
21/**
22 * A point in the GPX data
23 * @since 12167 implements ILatLon
24 */
25public class WayPoint extends WithAttributes implements Comparable<WayPoint>, TemplateEngineDataProvider, ILatLon {
26
27    /**
28     * The seconds (not milliseconds!) since 1970-01-01 00:00 UTC
29     */
30    public double time;
31    /**
32     * The color to draw the segment before this point in
33     * @see #drawLine
34     */
35    public Color customColoring;
36    /**
37     * <code>true</code> indicates that the line before this point should be drawn
38     */
39    public boolean drawLine;
40    /**
41     * The direction of the line before this point. Used as cache to speed up drawing. Should not be relied on.
42     */
43    public int dir;
44
45    /**
46     * Constructs a new {@code WayPoint} from an existing one.
47     * @param p existing waypoint
48     */
49    public WayPoint(WayPoint p) {
50        attr.putAll(p.attr);
51        lat = p.lat;
52        lon = p.lon;
53        east = p.east;
54        north = p.north;
55        eastNorthCacheKey = p.eastNorthCacheKey;
56        time = p.time;
57        customColoring = p.customColoring;
58        drawLine = p.drawLine;
59        dir = p.dir;
60    }
61
62    /**
63     * Constructs a new {@code WayPoint} from lat/lon coordinates.
64     * @param ll lat/lon coordinates
65     */
66    public WayPoint(LatLon ll) {
67        lat = ll.lat();
68        lon = ll.lon();
69    }
70
71    /*
72     * We "inline" lat/lon, rather than usinga LatLon internally => reduces memory overhead. Relevant
73     * because a lot of GPX waypoints are created when GPS tracks are downloaded from the OSM server.
74     */
75    private final double lat;
76    private final double lon;
77
78    /*
79     * internal cache of projected coordinates
80     */
81    private double east = Double.NaN;
82    private double north = Double.NaN;
83    private Object eastNorthCacheKey;
84
85    /**
86     * Invalidate the internal cache of east/north coordinates.
87     */
88    public void invalidateEastNorthCache() {
89        this.east = Double.NaN;
90        this.north = Double.NaN;
91    }
92
93    /**
94     * Returns the waypoint coordinates.
95     * @return the waypoint coordinates
96     */
97    public final LatLon getCoor() {
98        return new LatLon(lat, lon);
99    }
100
101    @Override
102    public double lon() {
103        return lon;
104    }
105
106    @Override
107    public double lat() {
108        return lat;
109    }
110
111    @Override
112    public final EastNorth getEastNorth(Projecting projecting) {
113        Object newCacheKey = projecting.getCacheKey();
114        if (Double.isNaN(east) || Double.isNaN(north) || !Objects.equals(newCacheKey, this.eastNorthCacheKey)) {
115            // projected coordinates haven't been calculated yet,
116            // so fill the cache of the projected waypoint coordinates
117            EastNorth en = projecting.latlon2eastNorth(this);
118            this.east = en.east();
119            this.north = en.north();
120            this.eastNorthCacheKey = newCacheKey;
121        }
122        return new EastNorth(east, north);
123    }
124
125    @Override
126    public String toString() {
127        return "WayPoint (" + (attr.containsKey(GPX_NAME) ? get(GPX_NAME) + ", " : "") + getCoor() + ", " + attr + ')';
128    }
129
130    /**
131     * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time.
132     *
133     * @param time the time to set
134     * @since 9383
135     */
136    public void setTime(Date time) {
137        this.time = time.getTime() / 1000.;
138        this.attr.put(PT_TIME, DateUtils.fromDate(time));
139    }
140
141    /**
142     * Convert the time stamp of the waypoint into seconds from the epoch.
143     *
144     * @deprecated call {@link #setTimeFromAttribute()} directly if you need this
145     */
146    @Deprecated
147    public void setTime() {
148        setTimeFromAttribute();
149    }
150
151    /**
152     * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time.
153     *
154     * @param ts seconds from the epoch
155     * @since 13210
156     */
157    public void setTime(long ts) {
158        this.time = ts;
159        this.attr.put(PT_TIME, DateUtils.fromTimestamp(ts));
160    }
161
162    /**
163     * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time.
164     *
165     * @param ts milliseconds from the epoch
166     * @since 14434
167     */
168    public void setTimeInMillis(long ts) {
169        this.time = ts / 1000.;
170        this.attr.put(PT_TIME, DateUtils.fromTimestampInMillis(ts));
171    }
172
173    /**
174     * Convert the time stamp of the waypoint into seconds from the epoch
175     * @return The parsed time if successful, or {@code null}
176     * @since 9383
177     */
178    public Date setTimeFromAttribute() {
179        if (attr.containsKey(PT_TIME)) {
180            try {
181                final Object obj = get(PT_TIME);
182                final Date date = obj instanceof Date ? (Date) obj : DateUtils.fromString(obj.toString());
183                time = date.getTime() / 1000.;
184                return date;
185            } catch (UncheckedParseException | DateTimeException e) {
186                Logging.warn(e);
187                time = 0;
188            }
189        }
190        return null;
191    }
192
193    @Override
194    public int compareTo(WayPoint w) {
195        return Double.compare(time, w.time);
196    }
197
198    /**
199     * Returns the waypoint time.
200     * @return the waypoint time
201     */
202    public Date getTime() {
203        return new Date((long) (time * 1000));
204    }
205
206    @Override
207    public Object getTemplateValue(String name, boolean special) {
208        if (!special)
209            return get(name);
210        else
211            return null;
212    }
213
214    @Override
215    public boolean evaluateCondition(Match condition) {
216        throw new UnsupportedOperationException();
217    }
218
219    @Override
220    public List<String> getTemplateKeys() {
221        return new ArrayList<>(attr.keySet());
222    }
223
224    @Override
225    public int hashCode() {
226        final int prime = 31;
227        int result = super.hashCode();
228        long temp = Double.doubleToLongBits(lat);
229        result = prime * result + (int) (temp ^ (temp >>> 32));
230        temp = Double.doubleToLongBits(lon);
231        result = prime * result + (int) (temp ^ (temp >>> 32));
232        temp = Double.doubleToLongBits(time);
233        result = prime * result + (int) (temp ^ (temp >>> 32));
234        return result;
235    }
236
237    @Override
238    public boolean equals(Object obj) {
239        if (this == obj)
240            return true;
241        if (obj == null || !super.equals(obj) || getClass() != obj.getClass())
242            return false;
243        WayPoint other = (WayPoint) obj;
244        return Double.doubleToLongBits(lat) == Double.doubleToLongBits(other.lat)
245            && Double.doubleToLongBits(lon) == Double.doubleToLongBits(other.lon)
246            && Double.doubleToLongBits(time) == Double.doubleToLongBits(other.time);
247    }
248}
Note: See TracBrowser for help on using the repository browser.