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