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

Last change on this file since 16488 was 16488, checked in by simon04, 4 years ago

fix #19281, see #19174 - Use Objects.hash where it is not used (patch by hiddewie, modified)

  • Property svn:eol-style set to native
File size: 8.9 KB
Line 
1// License: GPL. For details, see LICENSE file.
2package org.openstreetmap.josm.data.gpx;
3
4import java.awt.Color;
5import java.util.ArrayList;
6import java.util.Date;
7import java.util.HashMap;
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.Utils;
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 color to draw the segment before this point in
29 * @see #drawLine
30 */
31 public Color customColoring;
32
33 /**
34 * <code>true</code> indicates that the line before this point should be drawn
35 */
36 public boolean drawLine;
37
38 /**
39 * The direction of the line before this point. Used as cache to speed up drawing. Should not be relied on.
40 */
41 public int dir;
42
43 /*
44 * We "inline" lat/lon, rather than using a LatLon internally => reduces memory overhead. Relevant
45 * because a lot of GPX waypoints are created when GPS tracks are downloaded from the OSM server.
46 */
47 private final double lat;
48 private final double lon;
49
50 /*
51 * internal cache of projected coordinates
52 */
53 private double east = Double.NaN;
54 private double north = Double.NaN;
55 private Object eastNorthCacheKey;
56
57 /**
58 * Constructs a new {@code WayPoint} from an existing one.
59 *
60 * Except for PT_TIME attribute, all attribute objects are shallow copied.
61 * This means modification of attr objects will affect original and new {@code WayPoint}.
62 *
63 * @param p existing waypoint
64 */
65 public WayPoint(WayPoint p) {
66 attr = new LegacyMap();
67 attr.putAll(p.attr);
68 attr.put(PT_TIME, p.getDate());
69 lat = p.lat;
70 lon = p.lon;
71 east = p.east;
72 north = p.north;
73 eastNorthCacheKey = p.eastNorthCacheKey;
74 customColoring = p.customColoring;
75 drawLine = p.drawLine;
76 dir = p.dir;
77 }
78
79 /**
80 * Constructs a new {@code WayPoint} from lat/lon coordinates.
81 * @param ll lat/lon coordinates
82 */
83 public WayPoint(LatLon ll) {
84 attr = new LegacyMap();
85 lat = ll.lat();
86 lon = ll.lon();
87 }
88
89 /**
90 * Interim to detect legacy code that is not using {@code WayPoint.setTime(x)}
91 * functions, but {@code attr.put(PT_TIME, (String) x)} logic.
92 * To remove mid 2019
93 */
94 private static class LegacyMap extends HashMap<String, Object> {
95 private static final long serialVersionUID = 1;
96
97 LegacyMap() {
98 super(0);
99 }
100
101 @Override
102 public Object put(String key, Object value) {
103 Object ret = null;
104 if (!PT_TIME.equals(key) || value instanceof Date) {
105 ret = super.put(key, value);
106 } else if (value instanceof String) {
107 ret = super.put(PT_TIME, DateUtils.fromString((String) value));
108 List<String> lastErrorAndWarnings = Logging.getLastErrorAndWarnings();
109 if (!lastErrorAndWarnings.isEmpty() && !lastErrorAndWarnings.get(0).contains("calling WayPoint.put")) {
110 StackTraceElement[] e = Thread.currentThread().getStackTrace();
111 int n = 1;
112 while (n < e.length && "put".equals(e[n].getMethodName())) {
113 n++;
114 }
115 if (n < e.length) {
116 Logging.warn("{0}:{1} calling WayPoint.put(PT_TIME, ..) is deprecated. " +
117 "Use WayPoint.setTime(..) instead.", e[n].getClassName(), e[n].getMethodName());
118 }
119 }
120 }
121 return ret;
122 }
123 }
124
125 /**
126 * Invalidate the internal cache of east/north coordinates.
127 */
128 public void invalidateEastNorthCache() {
129 this.east = Double.NaN;
130 this.north = Double.NaN;
131 }
132
133 /**
134 * Returns the waypoint coordinates.
135 * @return the waypoint coordinates
136 */
137 public final LatLon getCoor() {
138 return new LatLon(lat, lon);
139 }
140
141 @Override
142 public double lon() {
143 return lon;
144 }
145
146 @Override
147 public double lat() {
148 return lat;
149 }
150
151 @Override
152 public final EastNorth getEastNorth(Projecting projecting) {
153 Object newCacheKey = projecting.getCacheKey();
154 if (Double.isNaN(east) || Double.isNaN(north) || !Objects.equals(newCacheKey, this.eastNorthCacheKey)) {
155 // projected coordinates haven't been calculated yet,
156 // so fill the cache of the projected waypoint coordinates
157 EastNorth en = projecting.latlon2eastNorth(this);
158 this.east = en.east();
159 this.north = en.north();
160 this.eastNorthCacheKey = newCacheKey;
161 }
162 return new EastNorth(east, north);
163 }
164
165 @Override
166 public String toString() {
167 return "WayPoint (" + (attr.containsKey(GPX_NAME) ? get(GPX_NAME) + ", " : "") + getCoor() + ", " + attr + ')';
168 }
169
170 /**
171 * Sets the {@link #PT_TIME} attribute to the specified time.
172 *
173 * @param time the time to set
174 * @since 9383
175 */
176 public void setTime(Date time) {
177 setTimeInMillis(time.getTime());
178 }
179
180 /**
181 * Sets the {@link #PT_TIME} attribute to the specified time.
182 *
183 * @param ts seconds from the epoch
184 * @since 13210
185 */
186 public void setTime(long ts) {
187 setTimeInMillis(ts * 1000);
188 }
189
190 /**
191 * Sets the {@link #PT_TIME} attribute to the specified time.
192 *
193 * @param ts milliseconds from the epoch
194 * @since 14434
195 */
196 public void setTimeInMillis(long ts) {
197 attr.put(PT_TIME, new Date(ts));
198 }
199
200 @Override
201 public int compareTo(WayPoint w) {
202 return Long.compare(getTimeInMillis(), w.getTimeInMillis());
203 }
204
205 /**
206 * Returns the waypoint time in seconds since the epoch.
207 *
208 * @return the waypoint time
209 */
210 public double getTime() {
211 return getTimeInMillis() / 1000.;
212 }
213
214 /**
215 * Returns the waypoint time in milliseconds since the epoch.
216 *
217 * @return the waypoint time
218 * @since 14456
219 */
220 public long getTimeInMillis() {
221 Date d = getDateImpl();
222 return d == null ? 0 : d.getTime();
223 }
224
225 /**
226 * Returns true if this waypoint has a time.
227 *
228 * @return true if a time is set, false otherwise
229 * @since 14456
230 */
231 public boolean hasDate() {
232 return attr.get(PT_TIME) instanceof Date;
233 }
234
235 /**
236 * Returns the waypoint time Date object.
237 *
238 * @return a copy of the Date object associated with this waypoint
239 * @since 14456
240 */
241 public Date getDate() {
242 return DateUtils.cloneDate(getDateImpl());
243 }
244
245 /**
246 * Returns the waypoint time Date object.
247 *
248 * @return the Date object associated with this waypoint
249 */
250 private Date getDateImpl() {
251 if (attr != null) {
252 final Object obj = attr.get(PT_TIME);
253
254 if (obj instanceof Date) {
255 return (Date) obj;
256 } else if (obj == null) {
257 Logging.info("Waypoint {0} value unset", PT_TIME);
258 } else {
259 Logging.warn("Unsupported waypoint {0} value: {1}", PT_TIME, obj);
260 }
261 }
262
263 return null;
264 }
265
266 @Override
267 public Object getTemplateValue(String name, boolean special) {
268 if (special) {
269 return null;
270 } else if ("desc".equals(name)) {
271 final Object value = get(name);
272 return value instanceof String ? Utils.stripHtml(((String) value)) : value;
273 } else {
274 return get(name);
275 }
276 }
277
278 @Override
279 public boolean evaluateCondition(Match condition) {
280 throw new UnsupportedOperationException();
281 }
282
283 @Override
284 public List<String> getTemplateKeys() {
285 return new ArrayList<>(attr.keySet());
286 }
287
288 @Override
289 public int hashCode() {
290 return Objects.hash(super.hashCode(), lat, lon, getTimeInMillis());
291 }
292
293 @Override
294 public boolean equals(Object obj) {
295 if (this == obj)
296 return true;
297 if (obj == null || !super.equals(obj) || getClass() != obj.getClass())
298 return false;
299 WayPoint other = (WayPoint) obj;
300 return Double.doubleToLongBits(lat) == Double.doubleToLongBits(other.lat)
301 && Double.doubleToLongBits(lon) == Double.doubleToLongBits(other.lon)
302 && getTimeInMillis() == other.getTimeInMillis();
303 }
304}
Note: See TracBrowser for help on using the repository browser.