Ignore:
Timestamp:
2018-11-27T21:40:10+01:00 (5 years ago)
Author:
Don-vip
Message:

fix #16995 - de-duplicate storage of timestamp within WayPoint and refactor some methods, added documentation, added some robustness against legacy code (will also log a warning if detected). Patch by cmuelle8, modified

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/org/openstreetmap/josm/data/gpx/WayPoint.java

    r14446 r14456  
    55import java.util.ArrayList;
    66import java.util.Date;
     7import java.util.HashMap;
    78import java.util.List;
    89import java.util.Objects;
     
    1415import org.openstreetmap.josm.data.projection.Projecting;
    1516import org.openstreetmap.josm.tools.Logging;
     17import org.openstreetmap.josm.tools.date.DateUtils;
    1618import org.openstreetmap.josm.tools.template_engine.TemplateEngineDataProvider;
    1719
     
    2325
    2426    /**
    25      * The seconds (not milliseconds!) since 1970-01-01 00:00 UTC
    26      */
    27     public double time;
    28     /**
    2927     * The color to draw the segment before this point in
    3028     * @see #drawLine
    3129     */
    3230    public Color customColoring;
     31
    3332    /**
    3433     * <code>true</code> indicates that the line before this point should be drawn
    3534     */
    3635    public boolean drawLine;
     36
    3737    /**
    3838     * The direction of the line before this point. Used as cache to speed up drawing. Should not be relied on.
     
    4040    public int dir;
    4141
     42    /*
     43     * We "inline" lat/lon, rather than using a LatLon internally => reduces memory overhead. Relevant
     44     * because a lot of GPX waypoints are created when GPS tracks are downloaded from the OSM server.
     45     */
     46    private final double lat;
     47    private final double lon;
     48
     49    /*
     50     * internal cache of projected coordinates
     51     */
     52    private double east = Double.NaN;
     53    private double north = Double.NaN;
     54    private Object eastNorthCacheKey;
     55
    4256    /**
    4357     * Constructs a new {@code WayPoint} from an existing one.
     58     *
     59     * Except for PT_TIME attribute, all attribute objects are shallow copied.
     60     * This means modification of attr objects will affect original and new {@code WayPoint}.
     61     *
    4462     * @param p existing waypoint
    4563     */
    4664    public WayPoint(WayPoint p) {
     65        init_attr();
    4766        attr.putAll(p.attr);
     67        attr.put(PT_TIME, p.getDate());
    4868        lat = p.lat;
    4969        lon = p.lon;
     
    5171        north = p.north;
    5272        eastNorthCacheKey = p.eastNorthCacheKey;
    53         time = p.time;
    5473        customColoring = p.customColoring;
    5574        drawLine = p.drawLine;
     
    6281     */
    6382    public WayPoint(LatLon ll) {
     83        init_attr();
    6484        lat = ll.lat();
    6585        lon = ll.lon();
    6686    }
    6787
    68     /*
    69      * We "inline" lat/lon, rather than usinga LatLon internally => reduces memory overhead. Relevant
    70      * because a lot of GPX waypoints are created when GPS tracks are downloaded from the OSM server.
    71      */
    72     private final double lat;
    73     private final double lon;
    74 
    75     /*
    76      * internal cache of projected coordinates
    77      */
    78     private double east = Double.NaN;
    79     private double north = Double.NaN;
    80     private Object eastNorthCacheKey;
     88    /**
     89     * Interim to detect legacy code that is not using {@code WayPoint.setTime(x)}
     90     * functions, but {@code attr.put(PT_TIME, (String) x)} logic.
     91     * To remove mid 2019
     92     */
     93    private void init_attr() {
     94        attr = new HashMap<String, Object>(0) {
     95            @Override
     96            public Object put(String key, Object value) {
     97                Object ret = null;
     98                if (key != PT_TIME || (key == PT_TIME && value instanceof Date)) {
     99                    ret = super.put(key, value);
     100                } else {
     101                    if (value instanceof String) {
     102                        ret = super.put(PT_TIME, DateUtils.fromString((String) value));
     103                        List<String> lastErrorAndWarnings = Logging.getLastErrorAndWarnings();
     104                        if (!lastErrorAndWarnings.isEmpty() && !lastErrorAndWarnings.get(0).contains("calling WayPoint.put")) {
     105                            StackTraceElement[] e = Thread.currentThread().getStackTrace();
     106                            int n = 1;
     107                            while (n < e.length && "put".equals(e[n].getMethodName())) {
     108                                n++;
     109                            }
     110                            if (n < e.length) {
     111                                Logging.warn("{0}:{1} calling WayPoint.put(PT_TIME, ..) is deprecated. " +
     112                                    "Use WayPoint.setTime(..) instead.", e[n].getClassName(), e[n].getMethodName());
     113                            }
     114                        }
     115                    }
     116                }
     117                return ret;
     118            }
     119        };
     120    }
    81121
    82122    /**
     
    126166
    127167    /**
    128      * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time.
     168     * Sets the {@link #PT_TIME} attribute to the specified time.
    129169     *
    130170     * @param time the time to set
     
    132172     */
    133173    public void setTime(Date time) {
    134         this.time = time.getTime() / 1000.;
    135         this.attr.put(PT_TIME, time);
     174        setTimeInMillis(time.getTime());
    136175    }
    137176
     
    139178     * Convert the time stamp of the waypoint into seconds from the epoch.
    140179     *
    141      * @deprecated call {@link #setTimeFromAttribute()} directly if you need this
     180     * @deprecated Use {@link #setTime(Date)}, {@link #setTime(long)}, {@link #setTimeInMillis(long)}
    142181     */
    143182    @Deprecated
     
    147186
    148187    /**
    149      * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time.
     188     * Sets the {@link #PT_TIME} attribute to the specified time.
    150189     *
    151190     * @param ts seconds from the epoch
     
    153192     */
    154193    public void setTime(long ts) {
    155         setTimeInMillis(ts*1000);
    156     }
    157 
    158     /**
    159      * Sets the {@link #time} field as well as the {@link #PT_TIME} attribute to the specified time.
     194        setTimeInMillis(ts * 1000);
     195    }
     196
     197    /**
     198     * Sets the {@link #PT_TIME} attribute to the specified time.
    160199     *
    161200     * @param ts milliseconds from the epoch
     
    163202     */
    164203    public void setTimeInMillis(long ts) {
    165         this.time = ts / 1000.;
    166         this.attr.put(PT_TIME, new Date(ts));
    167     }
    168 
    169     /**
    170      * Convert the time stamp of the waypoint into seconds from the epoch
     204        attr.put(PT_TIME, new Date(ts));
     205    }
     206
     207    /**
     208     * Convert the time stamp of the waypoint into seconds from the epoch.
    171209     * @return The parsed time if successful, or {@code null}
    172210     * @since 9383
    173      */
     211     * @deprecated Use {@link #setTime(Date)}, {@link #setTime(long)}, {@link #setTimeInMillis(long)}
     212     */
     213    @Deprecated
    174214    public Date setTimeFromAttribute() {
    175         if (attr.containsKey(PT_TIME)) {
    176             final Object obj = get(PT_TIME);
     215        Logging.warn("WayPoint.setTimeFromAttribute() is deprecated, please fix calling code");
     216        return getDate();
     217    }
     218
     219    @Override
     220    public int compareTo(WayPoint w) {
     221        return Long.compare(getTimeInMillis(), w.getTimeInMillis());
     222    }
     223
     224    /**
     225     * Returns the waypoint time in seconds since the epoch.
     226     *
     227     * @return the waypoint time
     228     */
     229    public double getTime() {
     230        return getTimeInMillis() / 1000.;
     231    }
     232
     233    /**
     234     * Returns the waypoint time in milliseconds since the epoch.
     235     *
     236     * @return the waypoint time
     237     * @since 14456
     238     */
     239    public long getTimeInMillis() {
     240        Date d = getDateImpl();
     241        return d == null ? 0 : d.getTime();
     242    }
     243
     244    /**
     245     * Returns true if this waypoint has a time.
     246     *
     247     * @return true if a time is set, false otherwise
     248     * @since 14456
     249     */
     250    public boolean hasDate() {
     251        return attr.get(PT_TIME) instanceof Date;
     252    }
     253
     254    /**
     255     * Returns the waypoint time Date object.
     256     *
     257     * @return a copy of the Date object associated with this waypoint
     258     * @since 14456
     259     */
     260    public Date getDate() {
     261        return DateUtils.cloneDate(getDateImpl());
     262    }
     263
     264    /**
     265     * Returns the waypoint time Date object.
     266     *
     267     * @return the Date object associated with this waypoint
     268     */
     269    private Date getDateImpl() {
     270        if (attr != null) {
     271            final Object obj = attr.get(PT_TIME);
     272
    177273            if (obj instanceof Date) {
    178                 final Date date = (Date) obj;
    179                 time = date.getTime() / 1000.;
    180                 return date;
     274                return (Date) obj;
    181275            } else if (obj == null) {
    182276                Logging.info("Waypoint {0} value unset", PT_TIME);
    183277            } else {
    184278                Logging.warn("Unsupported waypoint {0} value: {1}", PT_TIME, obj);
    185                 time = 0;
    186279            }
    187280        }
     281
    188282        return null;
    189     }
    190 
    191     @Override
    192     public int compareTo(WayPoint w) {
    193         return Double.compare(time, w.time);
    194     }
    195 
    196     /**
    197      * Returns the waypoint time.
    198      * @return the waypoint time
    199      */
    200     public Date getTime() {
    201         return new Date((long) (time * 1000));
    202283    }
    203284
     
    228309        temp = Double.doubleToLongBits(lon);
    229310        result = prime * result + (int) (temp ^ (temp >>> 32));
    230         temp = Double.doubleToLongBits(time);
     311        temp = getTimeInMillis();
    231312        result = prime * result + (int) (temp ^ (temp >>> 32));
    232313        return result;
     
    242323        return Double.doubleToLongBits(lat) == Double.doubleToLongBits(other.lat)
    243324            && Double.doubleToLongBits(lon) == Double.doubleToLongBits(other.lon)
    244             && Double.doubleToLongBits(time) == Double.doubleToLongBits(other.time);
     325            && getTimeInMillis() == other.getTimeInMillis();
    245326    }
    246327}
Note: See TracChangeset for help on using the changeset viewer.