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

Last change on this file since 14159 was 14159, checked in by Don-vip, 6 years ago

fix #16633 - add robustness against invalid time entries in GPX files

  • Property svn:eol-style set to native
File size: 6.8 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 public void setTime() {
145 setTimeFromAttribute();
146 }
147
148 /**
149 * Set the the time stamp of the waypoint into seconds from the epoch,
150 * @param time millisecond from the epoch
151 * @since 13210
152 */
153 public void setTime(long time) {
154 this.time = time / 1000.;
155 }
156
157 /**
158 * Convert the time stamp of the waypoint into seconds from the epoch
159 * @return The parsed time if successful, or {@code null}
160 * @since 9383
161 */
162 public Date setTimeFromAttribute() {
163 if (attr.containsKey(PT_TIME)) {
164 try {
165 final Object obj = get(PT_TIME);
166 final Date date = obj instanceof Date ? (Date) obj : DateUtils.fromString(obj.toString());
167 time = date.getTime() / 1000.;
168 return date;
169 } catch (UncheckedParseException | DateTimeException e) {
170 Logging.warn(e);
171 time = 0;
172 }
173 }
174 return null;
175 }
176
177 @Override
178 public int compareTo(WayPoint w) {
179 return Double.compare(time, w.time);
180 }
181
182 /**
183 * Returns the waypoint time.
184 * @return the waypoint time
185 */
186 public Date getTime() {
187 return new Date((long) (time * 1000));
188 }
189
190 @Override
191 public Object getTemplateValue(String name, boolean special) {
192 if (!special)
193 return get(name);
194 else
195 return null;
196 }
197
198 @Override
199 public boolean evaluateCondition(Match condition) {
200 throw new UnsupportedOperationException();
201 }
202
203 @Override
204 public List<String> getTemplateKeys() {
205 return new ArrayList<>(attr.keySet());
206 }
207
208 @Override
209 public int hashCode() {
210 final int prime = 31;
211 int result = super.hashCode();
212 long temp = Double.doubleToLongBits(lat);
213 result = prime * result + (int) (temp ^ (temp >>> 32));
214 temp = Double.doubleToLongBits(lon);
215 result = prime * result + (int) (temp ^ (temp >>> 32));
216 temp = Double.doubleToLongBits(time);
217 result = prime * result + (int) (temp ^ (temp >>> 32));
218 return result;
219 }
220
221 @Override
222 public boolean equals(Object obj) {
223 if (this == obj)
224 return true;
225 if (obj == null || !super.equals(obj) || getClass() != obj.getClass())
226 return false;
227 WayPoint other = (WayPoint) obj;
228 return Double.doubleToLongBits(lat) == Double.doubleToLongBits(other.lat)
229 && Double.doubleToLongBits(lon) == Double.doubleToLongBits(other.lon)
230 && Double.doubleToLongBits(time) == Double.doubleToLongBits(other.time);
231 }
232}
Note: See TracBrowser for help on using the repository browser.