    001// License: GPL. For details, see LICENSE file.
    002package org.openstreetmap.josm.plugins.streetside;
    003
    004import java.text.SimpleDateFormat;
    005import java.util.Calendar;
    006import java.util.Date;
    007import java.util.Locale;
    008
    009import org.openstreetmap.josm.data.coor.LatLon;
    010import org.openstreetmap.josm.plugins.streetside.utils.StreetsideProperties;
    011
    012/**
    013 * Abstract superclass for all image objects. At the moment there are just 2,
    014 * {@link StreetsideImportedImage} and {@link StreetsideImage}.
    015 *
    016 * @author nokutu
    017 *
    018 */
    019public abstract class StreetsideAbstractImage implements Comparable<StreetsideAbstractImage> {
    020        /**
    021         * If two values for field cd differ by less than EPSILON both values are
    022         * considered equal.
    023         */
    024        private static final float EPSILON = 1e-5f;
    025
    026        protected String id;
    027
    028        private long ne;
    029  private long pr;
    030
    031
    032        /** The time the image was captured, in Epoch format. */
    033        protected long cd;
    034        /** Sequence of pictures containing this object. */
    035        private StreetsideSequence sequence;
    036
    037        /** Position of the picture. */
    038        protected LatLon latLon;
    039        /** Direction of the picture. */
    040        protected double he;
    041        /** Temporal position of the picture until it is uploaded. */
    042        private LatLon tempLatLon;
    043        /**
    044         * When the object is being dragged in the map, the temporal position is stored
    045         * here.
    046         */
    047        private LatLon movingLatLon;
    048        /** Temporal direction of the picture until it is uploaded */
    049        private double tempHe;
    050        /**
    051         * When the object direction is being moved in the map, the temporal direction
    052         * is stored here
    053         */
    054        protected double movingHe;
    055        /** Whether the image must be drown in the map or not */
    056        private boolean visible;
    057
    058        /**
    059         * Creates a new object in the given position and with the given direction.
    060         * {@link LatLon}
    061         *
    062         * @param id - the Streetside image id
    063         *
    064         * @param latLon
    065         *            The latitude and longitude of the image.
    066         * @param he
    067         *            The direction of the picture (0 means north im Mapillary
    068         *            camera direction is not yet supported in the Streetside plugin).
    069         */
    070        protected StreetsideAbstractImage(final String id, final LatLon latLon, final double he) {
    071                this.id = id;
    072                this.latLon = latLon;
    073                tempLatLon = this.latLon;
    074                movingLatLon = this.latLon;
    075                this.he = he;
    076                tempHe = he;
    077                movingHe = he;
    078                visible = true;
    079        }
    080
    081        /**
    082         * Creates a new object with the given id.
    083         *
    084         * @param id - the image id (All images require ids in Streetside)
    085         */
    086        protected StreetsideAbstractImage(final String id) {
    087                this.id = id;
    088
    089                visible = true;
    090        }
    091
    092        /**
    093         * @return the id
    094         */
    095        public String getId() {
    096                return id;
    097        }
    098
    099        /**
    100         * @param id
    101         *            the id to set
    102         */
    103        public void setId(String id) {
    104                this.id = id;
    105        }
    106
    107        /**
    108         * Returns the original direction towards the image has been taken.
    109         *
    110         * @return The direction of the image (0 means north and goes clockwise).
    111         */
    112        public double getHe() {
    113                return he;
    114        }
    115
    116        /**
    117         * Returns the Epoch time when the image was captured.
    118         *
    119         * @return The long containing the Epoch time when the image was captured.
    120         */
    121        public long getCd() {
    122                return cd;
    123        }
    124
    125        /**
    126         * Returns the date the picture was taken in DMY format.
    127         *
    128         * @return A String object containing the date when the picture was taken.
    129         */
    130        public String getDate() {
    131                final StringBuilder format = new StringBuilder(26);
    132                format.append("m/d/YYYY");
    133                if (StreetsideProperties.DISPLAY_HOUR.get()) {
    134                        if (StreetsideProperties.TIME_FORMAT_24.get()) {
    135                                format.append(" - HH:mm:ss");
    136                        } else {
    137                                format.append(" - h:mm:ss a");
    138                        }
    139                }
    140                return getDate(format.toString());
    141        }
    142
    143        /**
    144         * Returns the date the picture was taken in the given format.
    145         *
    146         * @param format
    147         *            Format of the date. See {@link SimpleDateFormat}.
    148         * @return A String containing the date the picture was taken using the given
    149         *         format.
    150         * @throws NullPointerException
    151         *             if parameter format is <code>null</code>
    152         */
    153        public String getDate(String format) {
    154                final Date date = new Date(getCd());
    155                final SimpleDateFormat formatter = new SimpleDateFormat(format, Locale.US);
    156                formatter.setTimeZone(Calendar.getInstance().getTimeZone());
    157                return formatter.format(date);
    158        }
    159
    160        /**
    161         * Returns a LatLon object containing the original coordinates of the object.
    162         *
    163         * @return The LatLon object with the position of the object.
    164         */
    165        public LatLon getLatLon() {
    166                return latLon;
    167        }
    168
    169        /**
    170         * Returns the direction towards the image has been taken.
    171         *
    172         * @return The direction of the image (0 means north and goes clockwise).
    173         */
    174        public double getMovingHe() {
    175                return movingHe;
    176        }
    177
    178        /**
    179         * Returns a LatLon object containing the current coordinates of the object.
    180         * When you are dragging the image this changes.
    181         *
    182         * @return The LatLon object with the position of the object.
    183         */
    184        public LatLon getMovingLatLon() {
    185                return movingLatLon;
    186        }
    187
    188        /**
    189         * Returns the sequence which contains this image. Never null.
    190         *
    191         * @return The StreetsideSequence object that contains this StreetsideImage.
    192         */
    193
    194        public StreetsideSequence getSequence() {
    195                synchronized (this) {
    196                        if (sequence == null) {
    197                                sequence = new StreetsideSequence();
    198                                sequence.add(this);
    199                        }
    200                        return sequence;
    201                }
    202        }
    203
    204        /**
    205         * Returns the last fixed direction of the object.
    206         *
    207         * @return The last fixed direction of the object. 0 means north.
    208         */
    209        public double getTempHe() {
    210                return tempHe;
    211        }
    212
    213        /**
    214         * Returns the last fixed coordinates of the object.
    215         *
    216         * @return A LatLon object containing.
    217         */
    218        public LatLon getTempLatLon() {
    219                return tempLatLon;
    220        }
    221
    222        /**
    223         * Returns whether the object has been modified or not.
    224         *
    225         * @return true if the object has been modified; false otherwise.
    226         */
    227        public boolean isModified() {
    228                return !getMovingLatLon().equals(latLon) || Math.abs(getMovingHe() - cd) > EPSILON;
    229        }
    230
    231        /**
    232         * Returns whether the image is visible on the map or not.
    233         *
    234         * @return True if the image is visible; false otherwise.
    235         */
    236        public boolean isVisible() {
    237                return visible;
    238        }
    239
    240        /**
    241         * Moves the image temporally to another position
    242         *
    243         * @param x
    244         *            The movement of the image in longitude units.
    245         * @param y
    246         *            The movement of the image in latitude units.
    247         */
    248        public void move(final double x, final double y) {
    249                movingLatLon = new LatLon(tempLatLon.getY() + y, tempLatLon.getX() + x);
    250        }
    251
    252        /**
    253         * If the StreetsideImage belongs to a StreetsideSequence, returns the next
    254         * image in the sequence.
    255         *
    256         * @return The following StreetsideImage, or null if there is none.
    257         */
    258        public StreetsideAbstractImage next() {
    259                synchronized (this) {
    260                        return getSequence().next(this);
    261                }
    262        }
    263
    264        /**
    265         * If the StreetsideImage belongs to a StreetsideSequence, returns the previous
    266         * image in the sequence.
    267         *
    268         * @return The previous StreetsideImage, or null if there is none.
    269         */
    270        public StreetsideAbstractImage previous() {
    271                synchronized (this) {
    272                        return getSequence().previous(this);
    273                }
    274        }
    275
    276        public void setHe(final double he) {
    277                this.he = he;
    278        }
    279
    280        /**
    281         * Sets the Epoch time when the picture was captured.
    282         *
    283         * @param cd
    284         *            Epoch time when the image was captured.
    285         */
    286        public synchronized void setCd(final long cd) {
    287                this.cd = cd;
    288        }
    289
    290        public void setLatLon(final LatLon latLon) {
    291                if (latLon != null) {
    292                        this.latLon = latLon;
    293                }
    294        }
    295
    296        /**
    297         * Sets the StreetsideSequence object which contains the StreetsideImage.
    298         *
    299         * @param sequence
    300         *            The StreetsideSequence that contains the StreetsideImage.
    301         * @throws IllegalArgumentException
    302         *             if the image is not already part of the
    303         *             {@link StreetsideSequence}. Call
    304         *             {@link StreetsideSequence#add(StreetsideAbstractImage)} first.
    305         */
    306        public void setSequence(final StreetsideSequence sequence) {
    307                synchronized (this) {
    308                        if (sequence != null && !sequence.getImages().contains(this)) {
    309                                throw new IllegalArgumentException();
    310                        }
    311                        this.sequence = sequence;
    312                }
    313        }
    314
    315        /**
    316         * Set's whether the image should be visible on the map or not.
    317         *
    318         * @param visible
    319         *            true if the image is set to be visible; false otherwise.
    320         */
    321        public void setVisible(final boolean visible) {
    322                this.visible = visible;
    323        }
    324
    325        /**
    326         * Called when the mouse button is released, meaning that the picture has
    327         * stopped being dragged, so the temporal values are saved.
    328         */
    329        public void stopMoving() {
    330                tempLatLon = movingLatLon;
    331                tempHe = movingHe;
    332        }
    333
    334        /**
    335         * Turns the image direction.
    336         *
    337         * @param ca
    338         *            The angle the image is moving.
    339         */
    340        public void turn(final double ca) {
    341                movingHe = tempHe + ca;
    342        }
    343
    344        /**
    345   * @return the ne
    346   */
    347  public long getNe() {
    348    return ne;
    349  }
    350
    351  /**
    352   * @param ne the ne to set
    353   */
    354  public void setNe(long ne) {
    355    this.ne = ne;
    356  }
    357
    358  /**
    359   * @return the pr
    360   */
    361  public long getPr() {
    362    return pr;
    363  }
    364
    365  /**
    366   * @param pr the pr to set
    367   */
    368  public void setPr(long pr) {
    369    this.pr = pr;
    370  }
    371
    372
    373}