[6246] | 1 | // License: GPL. For details, see LICENSE file.
|
---|
[444] | 2 | package org.openstreetmap.josm.data.gpx;
|
---|
| 3 |
|
---|
[646] | 4 | import java.awt.Color;
|
---|
[4282] | 5 | import java.util.ArrayList;
|
---|
[2867] | 6 | import java.util.Date;
|
---|
[4282] | 7 | import java.util.List;
|
---|
[12167] | 8 | import java.util.Objects;
|
---|
[552] | 9 |
|
---|
[444] | 10 | import org.openstreetmap.josm.data.coor.EastNorth;
|
---|
[12167] | 11 | import org.openstreetmap.josm.data.coor.ILatLon;
|
---|
[444] | 12 | import org.openstreetmap.josm.data.coor.LatLon;
|
---|
[12656] | 13 | import org.openstreetmap.josm.data.osm.search.SearchCompiler.Match;
|
---|
[12167] | 14 | import org.openstreetmap.josm.data.projection.Projecting;
|
---|
[12620] | 15 | import org.openstreetmap.josm.tools.Logging;
|
---|
[10212] | 16 | import org.openstreetmap.josm.tools.UncheckedParseException;
|
---|
[9383] | 17 | import org.openstreetmap.josm.tools.date.DateUtils;
|
---|
[4282] | 18 | import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
|
---|
[444] | 19 |
|
---|
[12167] | 20 | /**
|
---|
| 21 | * A point in the GPX data
|
---|
| 22 | * @since 12167 implements ILatLon
|
---|
| 23 | */
|
---|
| 24 | public class WayPoint extends WithAttributes implements Comparable<WayPoint>, TemplateEngineDataProvider, ILatLon {
|
---|
[444] | 25 |
|
---|
[9738] | 26 | /**
|
---|
[10467] | 27 | * The seconds (not milliseconds!) since 1970-01-01 00:00 UTC
|
---|
[9738] | 28 | */
|
---|
[3321] | 29 | public double time;
|
---|
[12186] | 30 | /**
|
---|
| 31 | * The color to draw the segment before this point in
|
---|
| 32 | * @see #drawLine
|
---|
| 33 | */
|
---|
[3321] | 34 | public Color customColoring;
|
---|
[12186] | 35 | /**
|
---|
| 36 | * <code>true</code> indicates that the line before this point should be drawn
|
---|
| 37 | */
|
---|
[3321] | 38 | public boolean drawLine;
|
---|
[12186] | 39 | /**
|
---|
| 40 | * The direction of the line before this point. Used as cache to speed up drawing. Should not be relied on.
|
---|
| 41 | */
|
---|
[3321] | 42 | public int dir;
|
---|
| 43 |
|
---|
[11893] | 44 | /**
|
---|
| 45 | * Constructs a new {@code WayPoint} from an existing one.
|
---|
| 46 | * @param p existing waypoint
|
---|
| 47 | */
|
---|
[4129] | 48 | public WayPoint(WayPoint p) {
|
---|
| 49 | attr.putAll(p.attr);
|
---|
| 50 | lat = p.lat;
|
---|
| 51 | lon = p.lon;
|
---|
| 52 | east = p.east;
|
---|
| 53 | north = p.north;
|
---|
[12167] | 54 | eastNorthCacheKey = p.eastNorthCacheKey;
|
---|
[4129] | 55 | time = p.time;
|
---|
| 56 | customColoring = p.customColoring;
|
---|
| 57 | drawLine = p.drawLine;
|
---|
| 58 | dir = p.dir;
|
---|
| 59 | }
|
---|
| 60 |
|
---|
[11893] | 61 | /**
|
---|
| 62 | * Constructs a new {@code WayPoint} from lat/lon coordinates.
|
---|
| 63 | * @param ll lat/lon coordinates
|
---|
| 64 | */
|
---|
[3321] | 65 | public WayPoint(LatLon ll) {
|
---|
[4126] | 66 | lat = ll.lat();
|
---|
| 67 | lon = ll.lon();
|
---|
[3321] | 68 | }
|
---|
| 69 |
|
---|
[4126] | 70 | /*
|
---|
| 71 | * We "inline" lat/lon, rather than usinga LatLon internally => reduces memory overhead. Relevant
|
---|
| 72 | * because a lot of GPX waypoints are created when GPS tracks are downloaded from the OSM server.
|
---|
| 73 | */
|
---|
[6203] | 74 | private final double lat;
|
---|
| 75 | private final double lon;
|
---|
[1724] | 76 |
|
---|
[4126] | 77 | /*
|
---|
| 78 | * internal cache of projected coordinates
|
---|
| 79 | */
|
---|
| 80 | private double east = Double.NaN;
|
---|
| 81 | private double north = Double.NaN;
|
---|
[12199] | 82 | private Object eastNorthCacheKey;
|
---|
[4126] | 83 |
|
---|
| 84 | /**
|
---|
| 85 | * Invalidate the internal cache of east/north coordinates.
|
---|
| 86 | */
|
---|
| 87 | public void invalidateEastNorthCache() {
|
---|
| 88 | this.east = Double.NaN;
|
---|
| 89 | this.north = Double.NaN;
|
---|
| 90 | }
|
---|
| 91 |
|
---|
[11893] | 92 | /**
|
---|
| 93 | * Returns the waypoint coordinates.
|
---|
| 94 | * @return the waypoint coordinates
|
---|
| 95 | */
|
---|
[1724] | 96 | public final LatLon getCoor() {
|
---|
[8510] | 97 | return new LatLon(lat, lon);
|
---|
[1724] | 98 | }
|
---|
| 99 |
|
---|
[12167] | 100 | @Override
|
---|
| 101 | public double lon() {
|
---|
[12169] | 102 | return lon;
|
---|
[12167] | 103 | }
|
---|
| 104 |
|
---|
| 105 | @Override
|
---|
| 106 | public double lat() {
|
---|
[12169] | 107 | return lat;
|
---|
[12167] | 108 | }
|
---|
| 109 |
|
---|
| 110 | @Override
|
---|
| 111 | public final EastNorth getEastNorth(Projecting projecting) {
|
---|
| 112 | Object newCacheKey = projecting.getCacheKey();
|
---|
| 113 | if (Double.isNaN(east) || Double.isNaN(north) || !Objects.equals(newCacheKey, this.eastNorthCacheKey)) {
|
---|
[4126] | 114 | // projected coordinates haven't been calculated yet,
|
---|
| 115 | // so fill the cache of the projected waypoint coordinates
|
---|
[12167] | 116 | EastNorth en = projecting.latlon2eastNorth(this);
|
---|
[4126] | 117 | this.east = en.east();
|
---|
| 118 | this.north = en.north();
|
---|
[12167] | 119 | this.eastNorthCacheKey = newCacheKey;
|
---|
[4126] | 120 | }
|
---|
| 121 | return new EastNorth(east, north);
|
---|
[1724] | 122 | }
|
---|
| 123 |
|
---|
[1169] | 124 | @Override
|
---|
| 125 | public String toString() {
|
---|
[8846] | 126 | return "WayPoint (" + (attr.containsKey(GPX_NAME) ? get(GPX_NAME) + ", " : "") + getCoor() + ", " + attr + ')';
|
---|
[1169] | 127 | }
|
---|
[552] | 128 |
|
---|
[1169] | 129 | /**
|
---|
[9383] | 130 | * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time
|
---|
| 131 | *
|
---|
| 132 | * @param time the time to set
|
---|
| 133 | * @since 9383
|
---|
| 134 | */
|
---|
| 135 | public void setTime(Date time) {
|
---|
| 136 | this.time = time.getTime() / 1000.;
|
---|
| 137 | this.attr.put(PT_TIME, DateUtils.fromDate(time));
|
---|
| 138 | }
|
---|
| 139 |
|
---|
| 140 | /**
|
---|
[1169] | 141 | * Convert the time stamp of the waypoint into seconds from the epoch
|
---|
| 142 | */
|
---|
[1724] | 143 | public void setTime() {
|
---|
[9383] | 144 | setTimeFromAttribute();
|
---|
| 145 | }
|
---|
| 146 |
|
---|
| 147 | /**
|
---|
[13210] | 148 | * Set the the time stamp of the waypoint into seconds from the epoch,
|
---|
| 149 | * @param time millisecond from the epoch
|
---|
| 150 | * @since 13210
|
---|
| 151 | */
|
---|
| 152 | public void setTime(long time) {
|
---|
| 153 | this.time = time / 1000.;
|
---|
| 154 | }
|
---|
| 155 |
|
---|
| 156 | /**
|
---|
[9383] | 157 | * Convert the time stamp of the waypoint into seconds from the epoch
|
---|
| 158 | * @return The parsed time if successful, or {@code null}
|
---|
| 159 | * @since 9383
|
---|
| 160 | */
|
---|
| 161 | public Date setTimeFromAttribute() {
|
---|
[7518] | 162 | if (attr.containsKey(PT_TIME)) {
|
---|
[2874] | 163 | try {
|
---|
[9383] | 164 | final Date time = DateUtils.fromString(get(PT_TIME).toString());
|
---|
[9738] | 165 | this.time = time.getTime() / 1000.;
|
---|
[9383] | 166 | return time;
|
---|
[10212] | 167 | } catch (UncheckedParseException e) {
|
---|
[12620] | 168 | Logging.warn(e);
|
---|
[2874] | 169 | time = 0;
|
---|
[1721] | 170 | }
|
---|
[1185] | 171 | }
|
---|
[9383] | 172 | return null;
|
---|
[1169] | 173 | }
|
---|
| 174 |
|
---|
[6084] | 175 | @Override
|
---|
[4126] | 176 | public int compareTo(WayPoint w) {
|
---|
[1169] | 177 | return Double.compare(time, w.time);
|
---|
| 178 | }
|
---|
[2867] | 179 |
|
---|
[11893] | 180 | /**
|
---|
| 181 | * Returns the waypoint time.
|
---|
| 182 | * @return the waypoint time
|
---|
| 183 | */
|
---|
[2867] | 184 | public Date getTime() {
|
---|
| 185 | return new Date((long) (time * 1000));
|
---|
| 186 | }
|
---|
[4282] | 187 |
|
---|
| 188 | @Override
|
---|
[4431] | 189 | public Object getTemplateValue(String name, boolean special) {
|
---|
| 190 | if (!special)
|
---|
[7518] | 191 | return get(name);
|
---|
[4431] | 192 | else
|
---|
| 193 | return null;
|
---|
[4282] | 194 | }
|
---|
| 195 |
|
---|
| 196 | @Override
|
---|
| 197 | public boolean evaluateCondition(Match condition) {
|
---|
| 198 | throw new UnsupportedOperationException();
|
---|
| 199 | }
|
---|
| 200 |
|
---|
| 201 | @Override
|
---|
| 202 | public List<String> getTemplateKeys() {
|
---|
[7005] | 203 | return new ArrayList<>(attr.keySet());
|
---|
[4282] | 204 | }
|
---|
[10906] | 205 |
|
---|
| 206 | @Override
|
---|
| 207 | public int hashCode() {
|
---|
| 208 | final int prime = 31;
|
---|
| 209 | int result = super.hashCode();
|
---|
| 210 | long temp = Double.doubleToLongBits(lat);
|
---|
| 211 | result = prime * result + (int) (temp ^ (temp >>> 32));
|
---|
| 212 | temp = Double.doubleToLongBits(lon);
|
---|
| 213 | result = prime * result + (int) (temp ^ (temp >>> 32));
|
---|
| 214 | temp = Double.doubleToLongBits(time);
|
---|
| 215 | result = prime * result + (int) (temp ^ (temp >>> 32));
|
---|
| 216 | return result;
|
---|
| 217 | }
|
---|
| 218 |
|
---|
| 219 | @Override
|
---|
| 220 | public boolean equals(Object obj) {
|
---|
| 221 | if (this == obj)
|
---|
| 222 | return true;
|
---|
[11893] | 223 | if (obj == null || !super.equals(obj) || getClass() != obj.getClass())
|
---|
[10906] | 224 | return false;
|
---|
| 225 | WayPoint other = (WayPoint) obj;
|
---|
[11893] | 226 | return Double.doubleToLongBits(lat) == Double.doubleToLongBits(other.lat)
|
---|
| 227 | && Double.doubleToLongBits(lon) == Double.doubleToLongBits(other.lon)
|
---|
| 228 | && Double.doubleToLongBits(time) == Double.doubleToLongBits(other.time);
|
---|
[10906] | 229 | }
|
---|
[444] | 230 | }
|
---|