001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.gpx; 003 004import java.awt.Color; 005import java.util.ArrayList; 006import java.util.Date; 007import java.util.List; 008 009import org.openstreetmap.josm.Main; 010import org.openstreetmap.josm.actions.search.SearchCompiler.Match; 011import org.openstreetmap.josm.data.coor.EastNorth; 012import org.openstreetmap.josm.data.coor.LatLon; 013import org.openstreetmap.josm.data.projection.Projections; 014import org.openstreetmap.josm.tools.UncheckedParseException; 015import org.openstreetmap.josm.tools.date.DateUtils; 016import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider; 017 018public class WayPoint extends WithAttributes implements Comparable<WayPoint>, TemplateEngineDataProvider { 019 020 /** 021 * The seconds (not milliseconds!) since 1970-01-01 00:00 UTC 022 */ 023 public double time; 024 public Color customColoring; 025 public boolean drawLine; 026 public int dir; 027 028 public WayPoint(WayPoint p) { 029 attr.putAll(p.attr); 030 lat = p.lat; 031 lon = p.lon; 032 east = p.east; 033 north = p.north; 034 time = p.time; 035 customColoring = p.customColoring; 036 drawLine = p.drawLine; 037 dir = p.dir; 038 } 039 040 public WayPoint(LatLon ll) { 041 lat = ll.lat(); 042 lon = ll.lon(); 043 } 044 045 /* 046 * We "inline" lat/lon, rather than usinga LatLon internally => reduces memory overhead. Relevant 047 * because a lot of GPX waypoints are created when GPS tracks are downloaded from the OSM server. 048 */ 049 private final double lat; 050 private final double lon; 051 052 /* 053 * internal cache of projected coordinates 054 */ 055 private double east = Double.NaN; 056 private double north = Double.NaN; 057 058 /** 059 * Invalidate the internal cache of east/north coordinates. 060 */ 061 public void invalidateEastNorthCache() { 062 this.east = Double.NaN; 063 this.north = Double.NaN; 064 } 065 066 public final LatLon getCoor() { 067 return new LatLon(lat, lon); 068 } 069 070 /** 071 * <p>Replies the projected east/north coordinates.</p> 072 * 073 * <p>Uses the {@link Main#getProjection() global projection} to project the lan/lon-coordinates. 074 * Internally caches the projected coordinates.</p> 075 * 076 * <p><strong>Caveat:</strong> doesn't listen to projection changes. Clients must 077 * {@link #invalidateEastNorthCache() invalidate the internal cache}.</p> 078 * 079 * @return the east north coordinates or {@code null} 080 * @see #invalidateEastNorthCache() 081 */ 082 public final EastNorth getEastNorth() { 083 if (Double.isNaN(east) || Double.isNaN(north)) { 084 // projected coordinates haven't been calculated yet, 085 // so fill the cache of the projected waypoint coordinates 086 EastNorth en = Projections.project(new LatLon(lat, lon)); 087 this.east = en.east(); 088 this.north = en.north(); 089 } 090 return new EastNorth(east, north); 091 } 092 093 @Override 094 public String toString() { 095 return "WayPoint (" + (attr.containsKey(GPX_NAME) ? get(GPX_NAME) + ", " : "") + getCoor() + ", " + attr + ')'; 096 } 097 098 /** 099 * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time 100 * 101 * @param time the time to set 102 * @since 9383 103 */ 104 public void setTime(Date time) { 105 this.time = time.getTime() / 1000.; 106 this.attr.put(PT_TIME, DateUtils.fromDate(time)); 107 } 108 109 /** 110 * Convert the time stamp of the waypoint into seconds from the epoch 111 */ 112 public void setTime() { 113 setTimeFromAttribute(); 114 } 115 116 /** 117 * Convert the time stamp of the waypoint into seconds from the epoch 118 * @return The parsed time if successful, or {@code null} 119 * @since 9383 120 */ 121 public Date setTimeFromAttribute() { 122 if (attr.containsKey(PT_TIME)) { 123 try { 124 final Date time = DateUtils.fromString(get(PT_TIME).toString()); 125 this.time = time.getTime() / 1000.; 126 return time; 127 } catch (UncheckedParseException e) { 128 Main.warn(e); 129 time = 0; 130 } 131 } 132 return null; 133 } 134 135 @Override 136 public int compareTo(WayPoint w) { 137 return Double.compare(time, w.time); 138 } 139 140 public Date getTime() { 141 return new Date((long) (time * 1000)); 142 } 143 144 @Override 145 public Object getTemplateValue(String name, boolean special) { 146 if (!special) 147 return get(name); 148 else 149 return null; 150 } 151 152 @Override 153 public boolean evaluateCondition(Match condition) { 154 throw new UnsupportedOperationException(); 155 } 156 157 @Override 158 public List<String> getTemplateKeys() { 159 return new ArrayList<>(attr.keySet()); 160 } 161}