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