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