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