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}