Changeset 31278 in osm for applications
- Timestamp:
- 2015-06-18T18:08:53+02:00 (10 years ago)
- Location:
- applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary
- Files:
-
- 35 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryAbstractImage.java
r31264 r31278 12 12 public abstract class MapillaryAbstractImage { 13 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 14 /** Postion of the picture */ 15 public final LatLon latLon; 16 /** Direction of the picture */ 17 public final double ca; 18 public boolean isModified = false; 19 /** Temporal position of the picture until it is uplaoded */ 20 public LatLon tempLatLon; 21 /** 22 * When the object is being dragged in the map, the temporal position is 23 * stored here 24 */ 25 public LatLon movingLatLon; 26 /** Temporal direction of the picture until it is uplaoded */ 27 public double tempCa; 28 /** 29 * When the object direction is being moved in the map, the temporal 30 * direction is stored here 31 */ 32 protected double movingCa; 33 33 34 35 36 37 38 39 40 41 34 public MapillaryAbstractImage(double lat, double lon, double ca) { 35 this.latLon = new LatLon(lat, lon); 36 this.tempLatLon = this.latLon; 37 this.movingLatLon = this.latLon; 38 this.ca = ca; 39 this.tempCa = ca; 40 this.movingCa = ca; 41 } 42 42 43 44 45 46 47 48 49 50 43 /** 44 * Returns whether the object has been modified or not. 45 * 46 * @return true if the object has been modified; false otherwise. 47 */ 48 public boolean isModified() { 49 return this.isModified; 50 } 51 51 52 /** 53 * Returns a LatLon object containing the coordintes of the object. 54 * 55 * @return The LatLon object with the position of the object. 56 */ 57 public LatLon getLatLon() { 58 return movingLatLon; 59 } 52 /** 53 * Returns a LatLon object containing the current coordinates of the object. 54 * When you are dragging the image this changes. 55 * 56 * @return The LatLon object with the position of the object. 57 */ 58 public LatLon getLatLon() { 59 return movingLatLon; 60 } 60 61 61 public LatLon getTempLatLon() { 62 return tempLatLon; 63 } 62 /** 63 * Returns the last fixed coorditanes of the object. 64 * 65 * @return 66 */ 67 public LatLon getTempLatLon() { 68 return tempLatLon; 69 } 64 70 65 66 67 68 69 70 71 72 73 74 71 /** 72 * Moves the image temporally to another position 73 * 74 * @param pos 75 */ 76 public void move(double x, double y) { 77 this.movingLatLon = new LatLon(this.tempLatLon.getY() + y, 78 this.tempLatLon.getX() + x); 79 this.isModified = true; 80 } 75 81 76 77 78 79 80 81 82 83 84 82 /** 83 * Turns the image direction. 84 * 85 * @param ca 86 */ 87 public void turn(double ca) { 88 this.movingCa = this.tempCa + ca; 89 this.isModified = true; 90 } 85 91 86 87 88 89 90 91 92 93 92 /** 93 * Called when the mouse button is released, meaning that the picture has 94 * stopped being dragged. 95 */ 96 public void stopMoving() { 97 this.tempLatLon = this.movingLatLon; 98 this.tempCa = this.movingCa; 99 } 94 100 95 96 97 98 99 100 101 102 101 /** 102 * Returns the direction towards the image has been taken. 103 * 104 * @return The direction of the image (0 means north and goes clockwise). 105 */ 106 public double getCa() { 107 return movingCa; 108 } 103 109 104 105 106 107 108 109 110 111 110 /** 111 * Returns the last fixed direction of the object. 112 * 113 * @return 114 */ 115 public double getTempCa() { 116 return tempCa; 117 } 112 118 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryData.java
r31271 r31278 20 20 */ 21 21 public class MapillaryData implements ICachedLoaderListener { 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 22 public volatile static MapillaryData INSTANCE; 23 24 private final List<MapillaryAbstractImage> images; 25 private MapillaryAbstractImage selectedImage; 26 private MapillaryAbstractImage hoveredImage; 27 private final List<MapillaryAbstractImage> multiSelectedImages; 28 29 private List<MapillaryDataListener> listeners = new ArrayList<>(); 30 31 public MapillaryData() { 32 images = new CopyOnWriteArrayList<>(); 33 multiSelectedImages = new ArrayList<>(); 34 selectedImage = null; 35 } 36 37 public static MapillaryData getInstance() { 38 if (INSTANCE == null) { 39 INSTANCE = new MapillaryData(); 40 } 41 return INSTANCE; 42 } 43 44 /** 45 * Adds a set of MapillaryImages to the object, and then repaints mapView. 46 * 47 * @param images 48 * The set of images to be added. 49 */ 50 public synchronized void add(List<MapillaryAbstractImage> images) { 51 for (MapillaryAbstractImage image : images) { 52 add(image); 53 } 54 } 55 56 /** 57 * Adds an MapillaryImage to the object, and then repaints mapView. 58 * 59 * @param image 60 * The image to be added. 61 */ 62 public synchronized void add(MapillaryAbstractImage image) { 63 if (!images.contains(image)) { 64 this.images.add(image); 65 } 66 dataUpdated(); 67 } 68 69 public void addListener(MapillaryDataListener lis) { 70 listeners.add(lis); 71 } 72 73 public void removeListener(MapillaryDataListener lis) { 74 listeners.remove(lis); 75 } 76 77 /** 78 * Adds a set of MapillaryImages to the object, but doesn't repaint mapView. 79 * This is needed for concurrency. 80 * 81 * @param images 82 * The set of images to be added. 83 */ 84 public synchronized void addWithoutUpdate( 85 List<MapillaryAbstractImage> images) { 86 for (MapillaryAbstractImage image : images) { 87 addWithoutUpdate(image); 88 } 89 } 90 91 /** 92 * Sets the image under the mouse cursor. 93 * 94 * @param image 95 */ 96 public void setHoveredImage(MapillaryAbstractImage image) { 97 hoveredImage = image; 98 } 99 100 /** 101 * Returns the image under the mouse cursor. 102 * 103 * @return 104 */ 105 public MapillaryAbstractImage getHoveredImage() { 106 return hoveredImage; 107 } 108 109 /** 110 * Adds a MapillaryImage to the object, but doesn't repaint mapView. This is 111 * needed for concurrency. 112 * 113 * @param image 114 * The image to be added. 115 */ 116 public synchronized void addWithoutUpdate(MapillaryAbstractImage image) { 117 if (!images.contains(image)) { 118 this.images.add(image); 119 } 120 } 121 122 /** 123 * Repaints mapView object. 124 */ 125 public synchronized void dataUpdated() { 126 Main.map.mapView.repaint(); 127 } 128 129 /** 130 * Returns a List containing all images. 131 * 132 * @return A List object containing all images. 133 */ 134 public List<MapillaryAbstractImage> getImages() { 135 return images; 136 } 137 138 /** 139 * Returns the MapillaryImage object that is currently selected. 140 * 141 * @return The selected MapillaryImage object. 142 */ 143 public MapillaryAbstractImage getSelectedImage() { 144 return selectedImage; 145 } 146 147 /** 148 * If the selected MapillaryImage is part of a MapillarySequence then the 149 * following MapillaryImage is selected. In case there is none, does 150 * nothing. 151 */ 152 public void selectNext() { 153 if (getSelectedImage() instanceof MapillaryImage) { 154 if (getSelectedImage() == null) 155 return; 156 if (((MapillaryImage) getSelectedImage()).getSequence() == null) 157 return; 158 setSelectedImage(((MapillaryImage) getSelectedImage()).next(), true); 159 } 160 } 161 162 /** 163 * If the selected MapillaryImage is part of a MapillarySequence then the 164 * previous MapillaryImage is selected. In case there is none, does nothing. 165 */ 166 public void selectPrevious() { 167 if (getSelectedImage() instanceof MapillaryImage) { 168 if (getSelectedImage() == null) 169 return; 170 if (((MapillaryImage) getSelectedImage()).getSequence() == null) 171 throw new IllegalStateException(); 172 setSelectedImage(((MapillaryImage) getSelectedImage()).previous(), 173 true); 174 } 175 } 176 177 /** 178 * Selects a new image and then starts a new MapillaryImageDownloadThread 179 * thread in order to download its surrounding thumbnails. If the user does 180 * ctrl+click, this isn't triggered. 181 * 182 * @param image 183 * The MapillaryImage which is going to be selected 184 */ 185 public void setSelectedImage(MapillaryAbstractImage image) { 186 setSelectedImage(image, false); 187 } 188 189 /** 190 * Selects a new image and then starts a new MapillaryImageDownloadThread 191 * thread in order to download its surrounding thumbnails. If the user does 192 * ctrl+click, this isn't triggered. You can choose wheter to center the 193 * view on the new image or not. 194 * 195 * @param image 196 * @param zoom 197 */ 198 public void setSelectedImage(MapillaryAbstractImage image, boolean zoom) { 199 MapillaryAbstractImage oldImage = selectedImage; 200 selectedImage = image; 201 multiSelectedImages.clear(); 202 multiSelectedImages.add(image); 203 if (image != null) { 204 if (image instanceof MapillaryImage) { 205 MapillaryImage mapillaryImage = (MapillaryImage) image; 206 if (mapillaryImage.next() != null) { 207 new MapillaryCache(mapillaryImage.next().getKey(), 208 MapillaryCache.Type.THUMBNAIL).submit(this, false); 209 if (mapillaryImage.next().next() != null) 210 new MapillaryCache(mapillaryImage.next().next() 211 .getKey(), MapillaryCache.Type.THUMBNAIL) 212 .submit(this, false); 213 } 214 if (mapillaryImage.previous() != null) { 215 new MapillaryCache(mapillaryImage.previous().getKey(), 216 MapillaryCache.Type.THUMBNAIL).submit(this, false); 217 if (mapillaryImage.previous().previous() != null) 218 new MapillaryCache(mapillaryImage.previous().previous() 219 .getKey(), MapillaryCache.Type.THUMBNAIL) 220 .submit(this, false); 221 } 222 } 223 } 224 if (zoom) 225 Main.map.mapView.zoomTo(MapillaryData.getInstance() 226 .getSelectedImage().getLatLon()); 227 if (Main.map != null) { 228 Main.map.mapView.repaint(); 229 } 230 fireSelectedImageChanged(oldImage, selectedImage); 231 } 232 233 private void fireSelectedImageChanged(MapillaryAbstractImage oldImage, 234 MapillaryAbstractImage newImage) { 235 if (listeners.isEmpty()) 236 return; 237 for (MapillaryDataListener lis : listeners) 238 lis.selectedImageChanged(oldImage, newImage); 239 } 240 241 /** 242 * Adds a MapillaryImage object to the list of selected images, (when ctrl + 243 * click) 244 * 245 * @param image 246 * The MapillaryImage object to be added. 247 */ 248 public void addMultiSelectedImage(MapillaryAbstractImage image) { 249 if (!this.multiSelectedImages.contains(image)) { 250 if (this.getSelectedImage() != null) 251 this.multiSelectedImages.add(image); 252 else 253 this.setSelectedImage(image); 254 } 255 Main.map.mapView.repaint(); 256 } 257 258 /** 259 * Adds a set of MapillaryImage objects to the list of selected images. 260 * 261 * @param images 262 */ 263 public void addMultiSelectedImage(List<MapillaryAbstractImage> images) { 264 for (MapillaryAbstractImage image : images) 265 if (!this.multiSelectedImages.contains(image)) { 266 if (this.getSelectedImage() != null) 267 this.multiSelectedImages.add(image); 268 else 269 this.setSelectedImage(image); 270 } 271 Main.map.mapView.repaint(); 272 } 273 274 /** 275 * Returns a list containing all MapillaryImage objects selected with ctrl + 276 * click 277 * 278 * @return 279 */ 280 public List<MapillaryAbstractImage> getMultiSelectedImages() { 281 return multiSelectedImages; 282 } 283 284 /** 285 * This is empty because it is used just to make sure that certain images 286 * have already been downloaded. 287 */ 288 @Override 289 public void loadingFinished(CacheEntry data, 290 CacheEntryAttributes attributes, LoadResult result) { 291 // DO NOTHING 292 } 293 293 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryDataListener.java
r31266 r31278 2 2 3 3 public interface MapillaryDataListener { 4 /** 5 * Fired when the selected image is changed by something different from 6 * manually clicking on the icon. 7 */ 8 public void selectedImageChanged(MapillaryAbstractImage oldImage, MapillaryAbstractImage newImage); 4 /** 5 * Fired when the selected image is changed by something different from 6 * manually clicking on the icon. 7 */ 8 public void selectedImageChanged(MapillaryAbstractImage oldImage, 9 MapillaryAbstractImage newImage); 9 10 10 11 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImage.java
r31277 r31278 14 14 */ 15 15 public class MapillaryImage extends MapillaryAbstractImage { 16 17 18 /** Sequence of pictures containing this object*/19 16 /** Unique identifier of the object */ 17 private final String key; 18 /** Sequence of pictures containing this object */ 19 private MapillarySequence sequence; 20 20 21 private long capturedAt; 22 private String user; 23 private List<String> signs; 24 private String location; 21 /** Epoch time when the image was taken. */ 22 private long capturedAt; 23 /** The user that made the image */ 24 private String user; 25 /** Set of traffic signs in the image */ 26 private List<String> signs; 27 private String location; 25 28 26 27 28 29 public String getLocation() { 30 return location; 31 } 29 32 30 31 32 33 public void setLocation(String location) { 34 this.location = location; 35 } 33 36 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 37 /** 38 * Main contructor of the class MapillaryImage 39 * 40 * @param key 41 * The unique identifier of the image. 42 * @param lat 43 * The latitude where it is positioned. 44 * @param lon 45 * The longitude where it is positioned. 46 * @param ca 47 * The direction of the images in degrees, meaning 0 north. 48 */ 49 public MapillaryImage(String key, double lat, double lon, double ca) { 50 super(lat, lon, ca); 51 this.key = key; 52 this.signs = new ArrayList<>(); 53 } 51 54 52 /** 53 * Returns the unique identifier of the object. 54 * 55 * @return A String containing the unique identifier of the object. 56 */ 57 public String getKey() { 58 return this.key; 59 } 60 61 public void addSign(String sign) { 62 signs.add(sign); 63 } 64 65 public List<String> getSigns() { 66 return signs; 67 } 55 /** 56 * Returns the unique identifier of the object. 57 * 58 * @return A String containing the unique identifier of the object. 59 */ 60 public String getKey() { 61 return this.key; 62 } 68 63 69 public void setCapturedAt(long capturedAt) { 70 this.capturedAt = capturedAt; 71 } 64 /** 65 * Adds a new sign to the set of signs. 66 * 67 * @param sign 68 */ 69 public void addSign(String sign) { 70 signs.add(sign); 71 } 72 72 73 public long getCapturedAt() {74 return capturedAt;75 73 public List<String> getSigns() { 74 return signs; 75 } 76 76 77 public void setUser(String user) {78 this.user = user;79 77 public void setCapturedAt(long capturedAt) { 78 this.capturedAt = capturedAt; 79 } 80 80 81 public String getUser() {82 return user;83 81 public long getCapturedAt() { 82 return capturedAt; 83 } 84 84 85 /** 86 * Sets the MapillarySequence object which contains the MapillaryImage. 87 * 88 * @param sequence 89 * The MapillarySequence that contains the MapillaryImage. 90 */ 91 public void setSequence(MapillarySequence sequence) { 92 this.sequence = sequence; 93 } 85 public void setUser(String user) { 86 this.user = user; 87 } 94 88 95 /** 96 * Returns the sequence which contains this image. 97 * 98 * @return The MapillarySequence object that contains this MapillaryImage. 99 */ 100 public MapillarySequence getSequence() { 101 return this.sequence; 102 } 89 public String getUser() { 90 return user; 91 } 103 92 104 public String toString() { 105 return "Image[key=" + this.key + ";lat=" + this.latLon.lat() + ";lon=" 106 + this.latLon.lon() + ";ca=" + this.ca + "]"; 107 } 93 /** 94 * Sets the MapillarySequence object which contains the MapillaryImage. 95 * 96 * @param sequence 97 * The MapillarySequence that contains the MapillaryImage. 98 */ 99 public void setSequence(MapillarySequence sequence) { 100 this.sequence = sequence; 101 } 108 102 109 /** 110 * If the MapillaryImage belongs to a MapillarySequence, returns the next 111 * MapillarySequence in it. 112 * 113 * @return The following MapillaryImage, or null if there is none. 114 */ 115 public MapillaryImage next() { 116 if (this.getSequence() == null) 117 return null; 118 return this.getSequence().next(this); 119 } 103 /** 104 * Returns the sequence which contains this image. 105 * 106 * @return The MapillarySequence object that contains this MapillaryImage. 107 */ 108 public MapillarySequence getSequence() { 109 return this.sequence; 110 } 120 111 121 /** 122 * If the MapillaryImage belongs to a MapillarySequence, returns the 123 * previous MapillarySequence in it. 124 * 125 * @return The previous MapillaryImage, or null if there is none. 126 */ 127 public MapillaryImage previous() { 128 if (this.getSequence() == null) 129 return null; 130 return this.getSequence().previous(this); 131 } 132 133 public String getDate() { 134 return getDate("dd/MM/yyyy - hh:mm:ss"); 135 } 136 137 public String getDate(String format) { 138 Date date = new Date(getCapturedAt()); 112 public String toString() { 113 return "Image[key=" + this.key + ";lat=" + this.latLon.lat() + ";lon=" 114 + this.latLon.lon() + ";ca=" + this.ca + "]"; 115 } 139 116 140 SimpleDateFormat formatter = new SimpleDateFormat(format); 141 return formatter.format(date); 142 } 117 /** 118 * If the MapillaryImage belongs to a MapillarySequence, returns the next 119 * MapillarySequence in it. 120 * 121 * @return The following MapillaryImage, or null if there is none. 122 */ 123 public MapillaryImage next() { 124 if (this.getSequence() == null) 125 return null; 126 return this.getSequence().next(this); 127 } 143 128 144 @Override 145 public boolean equals(Object object) { 146 if (object instanceof MapillaryImage) 147 return this.key.equals(((MapillaryImage) object).getKey()); 148 return false; 149 } 129 /** 130 * If the MapillaryImage belongs to a MapillarySequence, returns the 131 * previous MapillarySequence in it. 132 * 133 * @return The previous MapillaryImage, or null if there is none. 134 */ 135 public MapillaryImage previous() { 136 if (this.getSequence() == null) 137 return null; 138 return this.getSequence().previous(this); 139 } 150 140 151 @Override 152 public int hashCode() { 153 return this.key.hashCode(); 154 } 141 /** 142 * Returns the date the picture was taken in DMY format. 143 * @return 144 */ 145 public String getDate() { 146 return getDate("dd/MM/yyyy - hh:mm:ss"); 147 } 148 149 /** 150 * Returns the date the picture was taken in the given format. 151 * @param format 152 * @return 153 */ 154 public String getDate(String format) { 155 Date date = new Date(getCapturedAt()); 156 157 SimpleDateFormat formatter = new SimpleDateFormat(format); 158 return formatter.format(date); 159 } 160 161 @Override 162 public boolean equals(Object object) { 163 if (object instanceof MapillaryImage) 164 return this.key.equals(((MapillaryImage) object).getKey()); 165 return false; 166 } 167 168 @Override 169 public int hashCode() { 170 return this.key.hashCode(); 171 } 155 172 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryImportedImage.java
r31277 r31278 9 9 public class MapillaryImportedImage extends MapillaryAbstractImage { 10 10 11 12 13 14 15 11 /** 12 * The picture file. 13 */ 14 protected File file; 15 public final String datetimeOriginal; 16 16 17 public MapillaryImportedImage(double lat, double lon, double ca, File file, String datetimeOriginal) { 18 super(lat, lon, ca); 19 this.file = file; 20 System.out.println(datetimeOriginal); 21 this.datetimeOriginal = datetimeOriginal; 22 } 17 public MapillaryImportedImage(double lat, double lon, double ca, File file, 18 String datetimeOriginal) { 19 super(lat, lon, ca); 20 this.file = file; 21 System.out.println(datetimeOriginal); 22 this.datetimeOriginal = datetimeOriginal; 23 } 23 24 24 /** 25 * Returns the pictures of the file. 26 * 27 * @return 28 * @throws IOException 29 */ 30 public BufferedImage getImage() throws IOException { 31 return ImageIO.read(file); 32 } 33 34 public File getFile() { 35 return file; 36 } 25 /** 26 * Returns the pictures of the file. 27 * 28 * @return 29 * @throws IOException 30 */ 31 public BufferedImage getImage() throws IOException { 32 return ImageIO.read(file); 33 } 37 34 38 @Override 39 public boolean equals(Object object) { 40 if (object instanceof MapillaryImportedImage) 41 return this.file.equals(((MapillaryImportedImage) object).file); 42 return false; 43 } 35 public File getFile() { 36 return file; 37 } 44 38 45 @Override 46 public int hashCode() { 47 return this.file.hashCode(); 48 } 39 @Override 40 public boolean equals(Object object) { 41 if (object instanceof MapillaryImportedImage) 42 return this.file.equals(((MapillaryImportedImage) object).file); 43 return false; 44 } 45 46 @Override 47 public int hashCode() { 48 return this.file.hashCode(); 49 } 49 50 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryLayer.java
r31277 r31278 53 53 54 54 public class MapillaryLayer extends AbstractModifiableLayer implements 55 DataSetListener, EditLayerChangeListener, LayerChangeListener { 56 57 public final static int SEQUENCE_MAX_JUMP_DISTANCE = Main.pref.getInteger( 58 "mapillary.sequence-max-jump-distance", 100); 59 60 public static MapillaryLayer INSTANCE; 61 public static CacheAccess<String, BufferedImageCacheEntry> CACHE; 62 public static MapillaryImage BLUE; 63 public static MapillaryImage RED; 64 65 private final MapillaryData mapillaryData = MapillaryData.getInstance(); 66 67 public List<Bounds> bounds; 68 69 private MapillaryToggleDialog mtd; 70 private MapillaryHistoryDialog mhd; 71 72 private MouseAdapter mouseAdapter; 73 74 int highlightPointRadius = Main.pref.getInteger( 75 "mappaint.highlight.radius", 7); 76 private int highlightStep = Main.pref.getInteger("mappaint.highlight.step", 77 4); 78 79 public MapillaryLayer() { 80 super(tr("Mapillary Images")); 81 bounds = new ArrayList<>(); 82 init(); 83 } 84 85 /** 86 * Initializes the Layer. 87 */ 88 private void init() { 89 MapillaryLayer.INSTANCE = this; 90 startMouseAdapter(); 91 try { 92 CACHE = JCSCacheManager.getCache("Mapillary"); 93 } catch (IOException e) { 94 Main.error(e); 95 } 96 if (Main.map != null && Main.map.mapView != null) { 97 Main.map.mapView.addMouseListener(mouseAdapter); 98 Main.map.mapView.addMouseMotionListener(mouseAdapter); 99 Main.map.mapView.addLayer(this); 100 MapView.addEditLayerChangeListener(this, false); 101 MapView.addLayerChangeListener(this); 102 Main.map.mapView.getEditLayer().data.addDataSetListener(this); 103 if (mtd == null) { 104 if (MapillaryToggleDialog.INSTANCE == null) { 105 mtd = MapillaryToggleDialog.getInstance(); 106 Main.map.addToggleDialog(mtd, false); 107 } else 108 mtd = MapillaryToggleDialog.getInstance(); 109 } 110 if (mhd == null) { 111 if (MapillaryHistoryDialog.INSTANCE == null) { 112 mhd = MapillaryHistoryDialog.getInstance(); 113 Main.map.addToggleDialog(mhd, false); 114 } else 115 mhd = MapillaryHistoryDialog.getInstance(); 116 } 117 } 118 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.EXPORT_MENU, true); 119 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.SIGN_MENU, true); 120 Main.map.mapView.setActiveLayer(this); 121 Main.map.repaint(); 122 } 123 124 public void startMouseAdapter() { 125 mouseAdapter = new MapillaryMouseAdapter(); 126 } 127 128 public synchronized static MapillaryLayer getInstance() { 129 if (MapillaryLayer.INSTANCE == null) 130 MapillaryLayer.INSTANCE = new MapillaryLayer(); 131 return MapillaryLayer.INSTANCE; 132 } 133 134 /** 135 * Downloads all images of the area covered by the OSM data. This is only 136 * just for automatic download. 137 */ 138 public void download() { 139 checkBigAreas(); 140 if (Main.pref.getBoolean("mapillary.download-manually")) 141 return; 142 for (Bounds bounds : Main.map.mapView.getEditLayer().data 143 .getDataSourceBounds()) { 144 if (!this.bounds.contains(bounds)) { 145 this.bounds.add(bounds); 146 new MapillaryDownloader().getImages(bounds.getMin(), 147 bounds.getMax()); 148 } 149 } 150 } 151 152 private void checkBigAreas() { 153 double area = 0; 154 for (Bounds bounds : Main.map.mapView.getEditLayer().data 155 .getDataSourceBounds()) { 156 area += bounds.getArea(); 157 } 158 if (area > MapillaryDownloadViewAction.MAX_AREA) { 159 Main.pref.put("mapillary.download-manually", true); 160 JOptionPane 161 .showMessageDialog( 162 Main.parent, 163 tr("The downloaded OSM area is too big. Download mode has been change to manual. You can change this back to automatic in preferences settings.")); 164 } 165 } 166 167 /** 168 * Returns the MapillaryData object, which acts as the database of the 169 * Layer. 170 * 171 * @return 172 */ 173 public MapillaryData getMapillaryData() { 174 return mapillaryData; 175 } 176 177 /** 178 * Method invoked when the layer is destroyed. 179 */ 180 @Override 181 public void destroy() { 182 MapillaryToggleDialog.getInstance().mapillaryImageDisplay 183 .setImage(null); 184 MapillaryData.getInstance().getImages().clear(); 185 MapillaryLayer.INSTANCE = null; 186 MapillaryData.INSTANCE = null; 187 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.EXPORT_MENU, false); 188 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.SIGN_MENU, false); 189 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.ZOOM_MENU, false); 190 Main.map.mapView.removeMouseListener(mouseAdapter); 191 Main.map.mapView.removeMouseMotionListener(mouseAdapter); 192 MapView.removeEditLayerChangeListener(this); 193 if (Main.map.mapView.getEditLayer() != null) 194 Main.map.mapView.getEditLayer().data.removeDataSetListener(this); 195 super.destroy(); 196 } 197 198 /** 199 * Returns true any of the images from the database has been modified. 200 */ 201 @Override 202 public boolean isModified() { 203 for (MapillaryAbstractImage image : mapillaryData.getImages()) 204 if (image.isModified()) 205 return true; 206 return false; 207 } 208 209 /** 210 * Paints the database in the map. 211 */ 212 @Override 213 public void paint(Graphics2D g, MapView mv, Bounds box) { 214 synchronized (this) { 215 // Draw colored lines 216 MapillaryLayer.BLUE = null; 217 MapillaryLayer.RED = null; 218 MapillaryToggleDialog.getInstance().blueButton.setEnabled(false); 219 MapillaryToggleDialog.getInstance().redButton.setEnabled(false); 220 if (mapillaryData.getSelectedImage() != null) { 221 MapillaryImage[] closestImages = getClosestImagesFromDifferentSequences(); 222 Point selected = mv.getPoint(mapillaryData.getSelectedImage() 223 .getLatLon()); 224 if (closestImages[0] != null) { 225 MapillaryLayer.BLUE = closestImages[0]; 226 g.setColor(Color.BLUE); 227 g.drawLine(mv.getPoint(closestImages[0].getLatLon()).x, 228 mv.getPoint(closestImages[0].getLatLon()).y, 229 selected.x, selected.y); 230 MapillaryToggleDialog.getInstance().blueButton 231 .setEnabled(true); 232 } 233 if (closestImages[1] != null) { 234 MapillaryLayer.RED = closestImages[1]; 235 g.setColor(Color.RED); 236 g.drawLine(mv.getPoint(closestImages[1].getLatLon()).x, 237 mv.getPoint(closestImages[1].getLatLon()).y, 238 selected.x, selected.y); 239 MapillaryToggleDialog.getInstance().redButton 240 .setEnabled(true); 241 } 242 } 243 g.setColor(Color.WHITE); 244 for (MapillaryAbstractImage imageAbs : mapillaryData.getImages()) { 245 Point p = mv.getPoint(imageAbs.getLatLon()); 246 if (imageAbs instanceof MapillaryImage) { 247 MapillaryImage image = (MapillaryImage) imageAbs; 248 Point nextp; 249 if (image.getSequence() != null 250 && image.getSequence().next(image) != null) { 251 nextp = mv.getPoint(image.getSequence().next(image) 252 .getLatLon()); 253 g.drawLine(p.x, p.y, nextp.x, nextp.y); 254 } 255 ImageIcon icon; 256 if (!mapillaryData.getMultiSelectedImages().contains(image)) 257 icon = MapillaryPlugin.MAP_ICON; 258 else 259 icon = MapillaryPlugin.MAP_ICON_SELECTED; 260 draw(g, image, icon, p); 261 if (!image.getSigns().isEmpty()) { 262 g.drawImage(MapillaryPlugin.MAP_SIGN.getImage(), p.x 263 + icon.getIconWidth() / 2, 264 p.y - icon.getIconHeight() / 2, 265 Main.map.mapView); 266 } 267 } else if (imageAbs instanceof MapillaryImportedImage) { 268 MapillaryImportedImage image = (MapillaryImportedImage) imageAbs; 269 ImageIcon icon; 270 if (!mapillaryData.getMultiSelectedImages().contains(image)) 271 icon = MapillaryPlugin.MAP_ICON_IMPORTED; 272 else 273 icon = MapillaryPlugin.MAP_ICON_SELECTED; 274 draw(g, image, icon, p); 275 } 276 } 277 } 278 } 279 280 /** 281 * Draws the highlight of the icon. 282 * 283 * @param g 284 * @param p 285 * @param size 286 */ 287 private void drawPointHighlight(Graphics2D g, Point p, int size) { 288 Color oldColor = g.getColor(); 289 Color highlightColor = PaintColors.HIGHLIGHT.get(); 290 Color highlightColorTransparent = new Color(highlightColor.getRed(), 291 highlightColor.getGreen(), highlightColor.getBlue(), 100); 292 g.setColor(highlightColorTransparent); 293 int s = size + highlightPointRadius; 294 while (s >= size) { 295 int r = (int) Math.floor(s / 2d); 296 g.fillRoundRect(p.x - r, p.y - r, s, s, r, r); 297 s -= highlightStep; 298 } 299 g.setColor(oldColor); 300 } 301 302 /** 303 * Draws the given icon of an image. Also checks if the mouse is over the 304 * image. 305 * 306 * @param g 307 * @param image 308 * @param icon 309 * @param p 310 */ 311 private void draw(Graphics2D g, MapillaryAbstractImage image, 312 ImageIcon icon, Point p) { 313 Image imagetemp = icon.getImage(); 314 BufferedImage bi = (BufferedImage) imagetemp; 315 int width = icon.getIconWidth(); 316 int height = icon.getIconHeight(); 317 318 // Rotate the image 319 double rotationRequired = Math.toRadians(image.getCa()); 320 double locationX = width / 2; 321 double locationY = height / 2; 322 AffineTransform tx = AffineTransform.getRotateInstance( 323 rotationRequired, locationX, locationY); 324 AffineTransformOp op = new AffineTransformOp(tx, 325 AffineTransformOp.TYPE_BILINEAR); 326 327 g.drawImage(op.filter(bi, null), p.x - (width / 2), p.y - (height / 2), 328 Main.map.mapView); 329 if (MapillaryData.getInstance().getHoveredImage() == image) { 330 drawPointHighlight(g, p, 16); 331 } 332 } 333 334 @Override 335 public Icon getIcon() { 336 return MapillaryPlugin.ICON16; 337 } 338 339 @Override 340 public boolean isMergable(Layer other) { 341 return false; 342 } 343 344 @Override 345 public void mergeFrom(Layer from) { 346 throw new UnsupportedOperationException( 347 "This layer does not support merging yet"); 348 } 349 350 @Override 351 public Action[] getMenuEntries() { 352 List<Action> actions = new ArrayList<>(); 353 actions.add(LayerListDialog.getInstance().createShowHideLayerAction()); 354 actions.add(LayerListDialog.getInstance().createDeleteLayerAction()); 355 actions.add(new LayerListPopup.InfoAction(this)); 356 return actions.toArray(new Action[actions.size()]); 357 } 358 359 private MapillaryImage[] getClosestImagesFromDifferentSequences() { 360 if (!(mapillaryData.getSelectedImage() instanceof MapillaryImage)) 361 return new MapillaryImage[2]; 362 MapillaryImage selected = (MapillaryImage) mapillaryData 363 .getSelectedImage(); 364 MapillaryImage[] ret = new MapillaryImage[2]; 365 double[] distances = { SEQUENCE_MAX_JUMP_DISTANCE, 366 SEQUENCE_MAX_JUMP_DISTANCE }; 367 LatLon selectedCoords = mapillaryData.getSelectedImage().getLatLon(); 368 for (MapillaryAbstractImage imagePrev : mapillaryData.getImages()) { 369 if (!(imagePrev instanceof MapillaryImage)) 370 continue; 371 MapillaryImage image = (MapillaryImage) imagePrev; 372 if (image.getLatLon().greatCircleDistance(selectedCoords) < SEQUENCE_MAX_JUMP_DISTANCE 373 && selected.getSequence() != image.getSequence()) { 374 if ((ret[0] == null && ret[1] == null) 375 || (image.getLatLon().greatCircleDistance( 376 selectedCoords) < distances[0] && (ret[1] == null || image 377 .getSequence() != ret[1].getSequence()))) { 378 ret[0] = image; 379 distances[0] = image.getLatLon().greatCircleDistance( 380 selectedCoords); 381 } else if ((ret[1] == null || image.getLatLon() 382 .greatCircleDistance(selectedCoords) < distances[1]) 383 && image.getSequence() != ret[0].getSequence()) { 384 ret[1] = image; 385 distances[1] = image.getLatLon().greatCircleDistance( 386 selectedCoords); 387 } 388 } 389 } 390 // Predownloads the thumbnails 391 if (ret[0] != null) 392 new MapillaryCache(ret[0].getKey(), MapillaryCache.Type.THUMBNAIL) 393 .submit(MapillaryData.getInstance(), false); 394 if (ret[1] != null) 395 new MapillaryCache(ret[1].getKey(), MapillaryCache.Type.THUMBNAIL) 396 .submit(MapillaryData.getInstance(), false); 397 return ret; 398 } 399 400 @Override 401 public Object getInfoComponent() { 402 StringBuilder sb = new StringBuilder(); 403 sb.append(tr("Mapillary layer")); 404 sb.append("\n"); 405 sb.append(tr("Total images:")); 406 sb.append(" "); 407 sb.append(this.size()); 408 sb.append("\n"); 409 return sb.toString(); 410 } 411 412 @Override 413 public String getToolTipText() { 414 return this.size() + " " + tr("images"); 415 } 416 417 private int size() { 418 return mapillaryData.getImages().size(); 419 } 420 421 // EditDataLayerChanged 422 @Override 423 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) { 424 } 425 426 /** 427 * When more data is downloaded, a delayed update is thrown, in order to 428 * wait for the data bounds to be set. 429 * 430 * @param event 431 */ 432 @Override 433 public void dataChanged(DataChangedEvent event) { 434 Main.worker.submit(new delayedDownload()); 435 } 436 437 private class delayedDownload extends Thread { 438 439 @Override 440 public void run() { 441 try { 442 sleep(1000); 443 } catch (InterruptedException e) { 444 Main.error(e); 445 } 446 MapillaryLayer.getInstance().download(); 447 } 448 } 449 450 @Override 451 public void primitivesAdded(PrimitivesAddedEvent event) { 452 } 453 454 @Override 455 public void primitivesRemoved(PrimitivesRemovedEvent event) { 456 } 457 458 @Override 459 public void tagsChanged(TagsChangedEvent event) { 460 } 461 462 @Override 463 public void nodeMoved(NodeMovedEvent event) { 464 } 465 466 @Override 467 public void wayNodesChanged(WayNodesChangedEvent event) { 468 } 469 470 @Override 471 public void relationMembersChanged(RelationMembersChangedEvent event) { 472 } 473 474 @Override 475 public void otherDatasetChange(AbstractDatasetChangedEvent event) { 476 } 477 478 @Override 479 public void visitBoundingBox(BoundingXYVisitor v) { 480 } 481 482 @Override 483 public void activeLayerChange(Layer oldLayer, Layer newLayer) { 484 if (newLayer == this) { 485 if (MapillaryData.getInstance().getImages().size() > 0) 486 Main.map.statusLine.setHelpText(tr("Total images: {0}", 487 MapillaryData.getInstance().getImages().size())); 488 else 489 Main.map.statusLine.setHelpText(tr("No images found")); 490 } 491 } 492 493 @Override 494 public void layerAdded(Layer newLayer) { 495 } 496 497 @Override 498 public void layerRemoved(Layer oldLayer) { 499 } 55 DataSetListener, EditLayerChangeListener, LayerChangeListener { 56 57 public final static int SEQUENCE_MAX_JUMP_DISTANCE = Main.pref.getInteger( 58 "mapillary.sequence-max-jump-distance", 100); 59 60 public static MapillaryLayer INSTANCE; 61 public static CacheAccess<String, BufferedImageCacheEntry> CACHE; 62 public static MapillaryImage BLUE; 63 public static MapillaryImage RED; 64 65 private final MapillaryData mapillaryData = MapillaryData.getInstance(); 66 67 public List<Bounds> bounds; 68 69 private MapillaryToggleDialog mtd; 70 private MapillaryHistoryDialog mhd; 71 72 private MouseAdapter mouseAdapter; 73 74 int highlightPointRadius = Main.pref.getInteger( 75 "mappaint.highlight.radius", 7); 76 private int highlightStep = Main.pref.getInteger("mappaint.highlight.step", 77 4); 78 79 public MapillaryLayer() { 80 super(tr("Mapillary Images")); 81 bounds = new ArrayList<>(); 82 init(); 83 } 84 85 /** 86 * Initializes the Layer. 87 */ 88 private void init() { 89 MapillaryLayer.INSTANCE = this; 90 startMouseAdapter(); 91 try { 92 CACHE = JCSCacheManager.getCache("Mapillary"); 93 } catch (IOException e) { 94 Main.error(e); 95 } 96 if (Main.map != null && Main.map.mapView != null) { 97 Main.map.mapView.addMouseListener(mouseAdapter); 98 Main.map.mapView.addMouseMotionListener(mouseAdapter); 99 Main.map.mapView.addLayer(this); 100 MapView.addEditLayerChangeListener(this, false); 101 MapView.addLayerChangeListener(this); 102 Main.map.mapView.getEditLayer().data.addDataSetListener(this); 103 if (mtd == null) { 104 if (MapillaryToggleDialog.INSTANCE == null) { 105 mtd = MapillaryToggleDialog.getInstance(); 106 Main.map.addToggleDialog(mtd, false); 107 } else 108 mtd = MapillaryToggleDialog.getInstance(); 109 } 110 if (mhd == null) { 111 if (MapillaryHistoryDialog.INSTANCE == null) { 112 mhd = MapillaryHistoryDialog.getInstance(); 113 Main.map.addToggleDialog(mhd, false); 114 } else 115 mhd = MapillaryHistoryDialog.getInstance(); 116 } 117 } 118 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.EXPORT_MENU, true); 119 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.SIGN_MENU, true); 120 Main.map.mapView.setActiveLayer(this); 121 Main.map.repaint(); 122 } 123 124 public void startMouseAdapter() { 125 mouseAdapter = new MapillaryMouseAdapter(); 126 } 127 128 public synchronized static MapillaryLayer getInstance() { 129 if (MapillaryLayer.INSTANCE == null) 130 MapillaryLayer.INSTANCE = new MapillaryLayer(); 131 return MapillaryLayer.INSTANCE; 132 } 133 134 /** 135 * Downloads all images of the area covered by the OSM data. This is only 136 * just for automatic download. 137 */ 138 public void download() { 139 checkBigAreas(); 140 if (Main.pref.getBoolean("mapillary.download-manually")) 141 return; 142 for (Bounds bounds : Main.map.mapView.getEditLayer().data 143 .getDataSourceBounds()) { 144 if (!this.bounds.contains(bounds)) { 145 this.bounds.add(bounds); 146 new MapillaryDownloader().getImages(bounds.getMin(), 147 bounds.getMax()); 148 } 149 } 150 } 151 152 /** 153 * Checks if the area of the OSM data is too big. This means that probably 154 * lots of Mapillary images are going to be downloaded, slowing down the 155 * program too much. To solve this the automatic is stopped, an alert is 156 * shown and you will have to download areas manually. 157 */ 158 private void checkBigAreas() { 159 double area = 0; 160 for (Bounds bounds : Main.map.mapView.getEditLayer().data 161 .getDataSourceBounds()) { 162 area += bounds.getArea(); 163 } 164 if (area > MapillaryDownloadViewAction.MAX_AREA) { 165 Main.pref.put("mapillary.download-manually", true); 166 JOptionPane 167 .showMessageDialog( 168 Main.parent, 169 tr("The downloaded OSM area is too big. Download mode has been change to manual. You can change this back to automatic in preferences settings.")); 170 } 171 } 172 173 /** 174 * Returns the MapillaryData object, which acts as the database of the 175 * Layer. 176 * 177 * @return 178 */ 179 public MapillaryData getMapillaryData() { 180 return mapillaryData; 181 } 182 183 /** 184 * Method invoked when the layer is destroyed. 185 */ 186 @Override 187 public void destroy() { 188 MapillaryToggleDialog.getInstance().mapillaryImageDisplay 189 .setImage(null); 190 MapillaryData.getInstance().getImages().clear(); 191 MapillaryLayer.INSTANCE = null; 192 MapillaryData.INSTANCE = null; 193 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.EXPORT_MENU, false); 194 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.SIGN_MENU, false); 195 MapillaryPlugin.setMenuEnabled(MapillaryPlugin.ZOOM_MENU, false); 196 Main.map.mapView.removeMouseListener(mouseAdapter); 197 Main.map.mapView.removeMouseMotionListener(mouseAdapter); 198 MapView.removeEditLayerChangeListener(this); 199 if (Main.map.mapView.getEditLayer() != null) 200 Main.map.mapView.getEditLayer().data.removeDataSetListener(this); 201 super.destroy(); 202 } 203 204 /** 205 * Returns true any of the images from the database has been modified. 206 */ 207 @Override 208 public boolean isModified() { 209 for (MapillaryAbstractImage image : mapillaryData.getImages()) 210 if (image.isModified()) 211 return true; 212 return false; 213 } 214 215 /** 216 * Paints the database in the map. 217 */ 218 @Override 219 public void paint(Graphics2D g, MapView mv, Bounds box) { 220 synchronized (this) { 221 // Draw colored lines 222 MapillaryLayer.BLUE = null; 223 MapillaryLayer.RED = null; 224 MapillaryToggleDialog.getInstance().blueButton.setEnabled(false); 225 MapillaryToggleDialog.getInstance().redButton.setEnabled(false); 226 if (mapillaryData.getSelectedImage() != null) { 227 MapillaryImage[] closestImages = getClosestImagesFromDifferentSequences(); 228 Point selected = mv.getPoint(mapillaryData.getSelectedImage() 229 .getLatLon()); 230 if (closestImages[0] != null) { 231 MapillaryLayer.BLUE = closestImages[0]; 232 g.setColor(Color.BLUE); 233 g.drawLine(mv.getPoint(closestImages[0].getLatLon()).x, 234 mv.getPoint(closestImages[0].getLatLon()).y, 235 selected.x, selected.y); 236 MapillaryToggleDialog.getInstance().blueButton 237 .setEnabled(true); 238 } 239 if (closestImages[1] != null) { 240 MapillaryLayer.RED = closestImages[1]; 241 g.setColor(Color.RED); 242 g.drawLine(mv.getPoint(closestImages[1].getLatLon()).x, 243 mv.getPoint(closestImages[1].getLatLon()).y, 244 selected.x, selected.y); 245 MapillaryToggleDialog.getInstance().redButton 246 .setEnabled(true); 247 } 248 } 249 g.setColor(Color.WHITE); 250 for (MapillaryAbstractImage imageAbs : mapillaryData.getImages()) { 251 Point p = mv.getPoint(imageAbs.getLatLon()); 252 if (imageAbs instanceof MapillaryImage) { 253 MapillaryImage image = (MapillaryImage) imageAbs; 254 Point nextp; 255 if (image.getSequence() != null 256 && image.getSequence().next(image) != null) { 257 nextp = mv.getPoint(image.getSequence().next(image) 258 .getLatLon()); 259 g.drawLine(p.x, p.y, nextp.x, nextp.y); 260 } 261 ImageIcon icon; 262 if (!mapillaryData.getMultiSelectedImages().contains(image)) 263 icon = MapillaryPlugin.MAP_ICON; 264 else 265 icon = MapillaryPlugin.MAP_ICON_SELECTED; 266 draw(g, image, icon, p); 267 if (!image.getSigns().isEmpty()) { 268 g.drawImage(MapillaryPlugin.MAP_SIGN.getImage(), p.x 269 + icon.getIconWidth() / 2, 270 p.y - icon.getIconHeight() / 2, 271 Main.map.mapView); 272 } 273 } else if (imageAbs instanceof MapillaryImportedImage) { 274 MapillaryImportedImage image = (MapillaryImportedImage) imageAbs; 275 ImageIcon icon; 276 if (!mapillaryData.getMultiSelectedImages().contains(image)) 277 icon = MapillaryPlugin.MAP_ICON_IMPORTED; 278 else 279 icon = MapillaryPlugin.MAP_ICON_SELECTED; 280 draw(g, image, icon, p); 281 } 282 } 283 } 284 } 285 286 /** 287 * Draws the highlight of the icon. 288 * 289 * @param g 290 * @param p 291 * @param size 292 */ 293 private void drawPointHighlight(Graphics2D g, Point p, int size) { 294 Color oldColor = g.getColor(); 295 Color highlightColor = PaintColors.HIGHLIGHT.get(); 296 Color highlightColorTransparent = new Color(highlightColor.getRed(), 297 highlightColor.getGreen(), highlightColor.getBlue(), 100); 298 g.setColor(highlightColorTransparent); 299 int s = size + highlightPointRadius; 300 while (s >= size) { 301 int r = (int) Math.floor(s / 2d); 302 g.fillRoundRect(p.x - r, p.y - r, s, s, r, r); 303 s -= highlightStep; 304 } 305 g.setColor(oldColor); 306 } 307 308 /** 309 * Draws the given icon of an image. Also checks if the mouse is over the 310 * image. 311 * 312 * @param g 313 * @param image 314 * @param icon 315 * @param p 316 */ 317 private void draw(Graphics2D g, MapillaryAbstractImage image, 318 ImageIcon icon, Point p) { 319 Image imagetemp = icon.getImage(); 320 BufferedImage bi = (BufferedImage) imagetemp; 321 int width = icon.getIconWidth(); 322 int height = icon.getIconHeight(); 323 324 // Rotate the image 325 double rotationRequired = Math.toRadians(image.getCa()); 326 double locationX = width / 2; 327 double locationY = height / 2; 328 AffineTransform tx = AffineTransform.getRotateInstance( 329 rotationRequired, locationX, locationY); 330 AffineTransformOp op = new AffineTransformOp(tx, 331 AffineTransformOp.TYPE_BILINEAR); 332 333 g.drawImage(op.filter(bi, null), p.x - (width / 2), p.y - (height / 2), 334 Main.map.mapView); 335 if (MapillaryData.getInstance().getHoveredImage() == image) { 336 drawPointHighlight(g, p, 16); 337 } 338 } 339 340 @Override 341 public Icon getIcon() { 342 return MapillaryPlugin.ICON16; 343 } 344 345 @Override 346 public boolean isMergable(Layer other) { 347 return false; 348 } 349 350 @Override 351 public void mergeFrom(Layer from) { 352 throw new UnsupportedOperationException( 353 "This layer does not support merging yet"); 354 } 355 356 @Override 357 public Action[] getMenuEntries() { 358 List<Action> actions = new ArrayList<>(); 359 actions.add(LayerListDialog.getInstance().createShowHideLayerAction()); 360 actions.add(LayerListDialog.getInstance().createDeleteLayerAction()); 361 actions.add(new LayerListPopup.InfoAction(this)); 362 return actions.toArray(new Action[actions.size()]); 363 } 364 365 private MapillaryImage[] getClosestImagesFromDifferentSequences() { 366 if (!(mapillaryData.getSelectedImage() instanceof MapillaryImage)) 367 return new MapillaryImage[2]; 368 MapillaryImage selected = (MapillaryImage) mapillaryData 369 .getSelectedImage(); 370 MapillaryImage[] ret = new MapillaryImage[2]; 371 double[] distances = { SEQUENCE_MAX_JUMP_DISTANCE, 372 SEQUENCE_MAX_JUMP_DISTANCE }; 373 LatLon selectedCoords = mapillaryData.getSelectedImage().getLatLon(); 374 for (MapillaryAbstractImage imagePrev : mapillaryData.getImages()) { 375 if (!(imagePrev instanceof MapillaryImage)) 376 continue; 377 MapillaryImage image = (MapillaryImage) imagePrev; 378 if (image.getLatLon().greatCircleDistance(selectedCoords) < SEQUENCE_MAX_JUMP_DISTANCE 379 && selected.getSequence() != image.getSequence()) { 380 if ((ret[0] == null && ret[1] == null) 381 || (image.getLatLon().greatCircleDistance( 382 selectedCoords) < distances[0] && (ret[1] == null || image 383 .getSequence() != ret[1].getSequence()))) { 384 ret[0] = image; 385 distances[0] = image.getLatLon().greatCircleDistance( 386 selectedCoords); 387 } else if ((ret[1] == null || image.getLatLon() 388 .greatCircleDistance(selectedCoords) < distances[1]) 389 && image.getSequence() != ret[0].getSequence()) { 390 ret[1] = image; 391 distances[1] = image.getLatLon().greatCircleDistance( 392 selectedCoords); 393 } 394 } 395 } 396 // Predownloads the thumbnails 397 if (ret[0] != null) 398 new MapillaryCache(ret[0].getKey(), MapillaryCache.Type.THUMBNAIL) 399 .submit(MapillaryData.getInstance(), false); 400 if (ret[1] != null) 401 new MapillaryCache(ret[1].getKey(), MapillaryCache.Type.THUMBNAIL) 402 .submit(MapillaryData.getInstance(), false); 403 return ret; 404 } 405 406 @Override 407 public Object getInfoComponent() { 408 StringBuilder sb = new StringBuilder(); 409 sb.append(tr("Mapillary layer")); 410 sb.append("\n"); 411 sb.append(tr("Total images:")); 412 sb.append(" "); 413 sb.append(this.size()); 414 sb.append("\n"); 415 return sb.toString(); 416 } 417 418 @Override 419 public String getToolTipText() { 420 return this.size() + " " + tr("images"); 421 } 422 423 private int size() { 424 return mapillaryData.getImages().size(); 425 } 426 427 // EditDataLayerChanged 428 @Override 429 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) { 430 } 431 432 /** 433 * When more data is downloaded, a delayed update is thrown, in order to 434 * wait for the data bounds to be set. 435 * 436 * @param event 437 */ 438 @Override 439 public void dataChanged(DataChangedEvent event) { 440 Main.worker.submit(new delayedDownload()); 441 } 442 443 private class delayedDownload extends Thread { 444 445 @Override 446 public void run() { 447 try { 448 sleep(1000); 449 } catch (InterruptedException e) { 450 Main.error(e); 451 } 452 MapillaryLayer.getInstance().download(); 453 } 454 } 455 456 @Override 457 public void primitivesAdded(PrimitivesAddedEvent event) { 458 } 459 460 @Override 461 public void primitivesRemoved(PrimitivesRemovedEvent event) { 462 } 463 464 @Override 465 public void tagsChanged(TagsChangedEvent event) { 466 } 467 468 @Override 469 public void nodeMoved(NodeMovedEvent event) { 470 } 471 472 @Override 473 public void wayNodesChanged(WayNodesChangedEvent event) { 474 } 475 476 @Override 477 public void relationMembersChanged(RelationMembersChangedEvent event) { 478 } 479 480 @Override 481 public void otherDatasetChange(AbstractDatasetChangedEvent event) { 482 } 483 484 @Override 485 public void visitBoundingBox(BoundingXYVisitor v) { 486 } 487 488 @Override 489 public void activeLayerChange(Layer oldLayer, Layer newLayer) { 490 if (newLayer == this) { 491 if (MapillaryData.getInstance().getImages().size() > 0) 492 Main.map.statusLine.setHelpText(tr("Total images: {0}", 493 MapillaryData.getInstance().getImages().size())); 494 else 495 Main.map.statusLine.setHelpText(tr("No images found")); 496 } 497 } 498 499 @Override 500 public void layerAdded(Layer newLayer) { 501 } 502 503 @Override 504 public void layerRemoved(Layer oldLayer) { 505 } 500 506 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryMouseAdapter.java
r31277 r31278 22 22 */ 23 23 public class MapillaryMouseAdapter extends MouseAdapter { 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 24 private Point start; 25 private int lastButton; 26 private MapillaryAbstractImage closest; 27 private MapillaryAbstractImage lastClicked; 28 private MapillaryData mapillaryData; 29 private MapillaryRecord record; 30 31 private boolean nothingHighlighted; 32 33 public MapillaryMouseAdapter() { 34 mapillaryData = MapillaryData.getInstance(); 35 record = MapillaryRecord.getInstance(); 36 } 37 38 @Override 39 public void mousePressed(MouseEvent e) { 40 lastButton = e.getButton(); 41 if (e.getButton() != MouseEvent.BUTTON1) 42 return; 43 MapillaryAbstractImage closestTemp = getClosest(e.getPoint()); 44 if (Main.map.mapView.getActiveLayer() instanceof OsmDataLayer 45 && closestTemp != null) { 46 this.lastClicked = this.closest; 47 MapillaryData.getInstance().setSelectedImage(closestTemp); 48 return; 49 } else if (Main.map.mapView.getActiveLayer() != MapillaryLayer 50 .getInstance()) 51 return; 52 if (closestTemp instanceof MapillaryImage || closestTemp == null) { 53 MapillaryImage closest = (MapillaryImage) closestTemp; 54 // Doube click 55 if (e.getClickCount() == 2 56 && mapillaryData.getSelectedImage() != null 57 && closest != null) { 58 for (MapillaryAbstractImage img : closest.getSequence() 59 .getImages()) { 60 mapillaryData.addMultiSelectedImage(img); 61 } 62 } 63 this.start = e.getPoint(); 64 this.lastClicked = this.closest; 65 this.closest = closest; 66 if (mapillaryData.getMultiSelectedImages().contains(closest)) 67 return; 68 // ctrl+click 69 if (e.getModifiers() == (MouseEvent.BUTTON1_MASK | MouseEvent.CTRL_MASK) 70 && closest != null) 71 mapillaryData.addMultiSelectedImage(closest); 72 // shift + click 73 else if (e.getModifiers() == (MouseEvent.BUTTON1_MASK | MouseEvent.SHIFT_MASK) 74 && this.closest instanceof MapillaryImage 75 && this.lastClicked instanceof MapillaryImage) { 76 if (this.closest != null 77 && this.lastClicked != null 78 && ((MapillaryImage) this.closest).getSequence() == ((MapillaryImage) this.lastClicked) 79 .getSequence()) { 80 int i = ((MapillaryImage) this.closest).getSequence() 81 .getImages().indexOf(this.closest); 82 int j = ((MapillaryImage) this.lastClicked).getSequence() 83 .getImages().indexOf(this.lastClicked); 84 if (i < j) 85 mapillaryData 86 .addMultiSelectedImage(new ArrayList<MapillaryAbstractImage>( 87 ((MapillaryImage) this.closest) 88 .getSequence().getImages() 89 .subList(i, j + 1))); 90 else 91 mapillaryData 92 .addMultiSelectedImage(new ArrayList<MapillaryAbstractImage>( 93 ((MapillaryImage) this.closest) 94 .getSequence().getImages() 95 .subList(j, i + 1))); 96 } 97 // click 98 } else 99 mapillaryData.setSelectedImage(closest); 100 // If you select an imported image 101 } else if (closestTemp instanceof MapillaryImportedImage) { 102 MapillaryImportedImage closest = (MapillaryImportedImage) closestTemp; 103 this.start = e.getPoint(); 104 this.lastClicked = this.closest; 105 this.closest = closest; 106 if (mapillaryData.getMultiSelectedImages().contains(closest)) 107 return; 108 if (e.getModifiers() == (MouseEvent.BUTTON1_MASK | MouseEvent.CTRL_MASK) 109 && closest != null) 110 mapillaryData.addMultiSelectedImage(closest); 111 else 112 mapillaryData.setSelectedImage(closest); 113 } 114 } 115 116 private MapillaryAbstractImage getClosest(Point clickPoint) { 117 double snapDistance = 10; 118 double minDistance = Double.MAX_VALUE; 119 MapillaryAbstractImage closest = null; 120 for (MapillaryAbstractImage image : mapillaryData.getImages()) { 121 Point imagePoint = Main.map.mapView.getPoint(image.getLatLon()); 122 imagePoint.setLocation(imagePoint.getX(), imagePoint.getY()); 123 double dist = clickPoint.distanceSq(imagePoint); 124 if (minDistance > dist 125 && clickPoint.distance(imagePoint) < snapDistance) { 126 minDistance = dist; 127 closest = image; 128 } 129 } 130 return closest; 131 } 132 133 @Override 134 public void mouseDragged(MouseEvent e) { 135 if (Main.map.mapView.getActiveLayer() != MapillaryLayer.getInstance()) 136 return; 137 138 if (!Main.pref.getBoolean("mapillary.developer")) 139 for (MapillaryAbstractImage img : MapillaryData.getInstance() 140 .getMultiSelectedImages()) { 141 if (img instanceof MapillaryImage) 142 return; 143 } 144 if (MapillaryData.getInstance().getSelectedImage() != null) { 145 if (lastButton == MouseEvent.BUTTON1 && !e.isShiftDown()) { 146 LatLon to = Main.map.mapView.getLatLon(e.getX(), e.getY()); 147 LatLon from = Main.map.mapView.getLatLon(start.getX(), 148 start.getY()); 149 for (MapillaryAbstractImage img : MapillaryData.getInstance() 150 .getMultiSelectedImages()) { 151 152 img.move(to.getX() - from.getX(), to.getY() - from.getY()); 153 } 154 Main.map.repaint(); 155 } else if (lastButton == MouseEvent.BUTTON1 && e.isShiftDown()) { 156 this.closest.turn(Math.toDegrees(Math.atan2( 157 (e.getX() - start.x), -(e.getY() - start.y))) 158 - closest.getTempCa()); 159 for (MapillaryAbstractImage img : MapillaryData.getInstance() 160 .getMultiSelectedImages()) { 161 img.turn(Math.toDegrees(Math.atan2((e.getX() - start.x), 162 -(e.getY() - start.y))) - closest.getTempCa()); 163 } 164 Main.map.repaint(); 165 } 166 } 167 } 168 169 @Override 170 public void mouseReleased(MouseEvent e) { 171 if (mapillaryData.getSelectedImage() == null) 172 return; 173 if (mapillaryData.getSelectedImage().getTempCa() != mapillaryData 174 .getSelectedImage().getCa()) { 175 double from = mapillaryData.getSelectedImage().getTempCa(); 176 double to = mapillaryData.getSelectedImage().getCa(); 177 record.addCommand(new CommandTurnImage(mapillaryData 178 .getMultiSelectedImages(), to - from)); 179 } else if (mapillaryData.getSelectedImage().getTempLatLon() != mapillaryData 180 .getSelectedImage().getLatLon()) { 181 LatLon from = mapillaryData.getSelectedImage().getTempLatLon(); 182 LatLon to = mapillaryData.getSelectedImage().getLatLon(); 183 record.addCommand(new CommandMoveImage(mapillaryData 184 .getMultiSelectedImages(), to.getX() - from.getX(), to 185 .getY() - from.getY())); 186 } 187 for (MapillaryAbstractImage img : mapillaryData 188 .getMultiSelectedImages()) { 189 if (img != null) 190 img.stopMoving(); 191 } 192 } 193 194 /** 195 * Checks if the mouse is over pictures. 196 */ 197 @Override 198 public void mouseMoved(MouseEvent e) { 199 MapillaryAbstractImage closestTemp = getClosest(e.getPoint()); 200 201 if (closestTemp != null 202 && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer 203 && Main.map.mapModeSelect.getValue("active") == Boolean.TRUE) { 204 Main.map.mapModeSelect.exitMode(); 205 } else if (closestTemp == null 206 && Main.map.mapView.getActiveLayer() instanceof OsmDataLayer 207 && Main.map.mapModeSelect.getValue("active") == Boolean.FALSE) { 208 Main.map.mapModeSelect.enterMode(); 209 nothingHighlighted = false; 210 } else if (Main.map.mapModeSelect.getValue("active") == Boolean.FALSE 211 && !nothingHighlighted) { 212 for (OsmPrimitive primivitive : Main.map.mapView.getEditLayer().data 213 .allPrimitives()) { 214 primivitive.setHighlighted(false); 215 } 216 nothingHighlighted = true; 217 } 218 219 // TODO check if it is possible to do this while the OSM data layer is 220 // selected. 221 if (MapillaryData.getInstance().getHoveredImage() != closestTemp 222 && closestTemp != null) { 223 MapillaryData.getInstance().setHoveredImage(closestTemp); 224 MapillaryToggleDialog.getInstance().setImage(closestTemp); 225 MapillaryToggleDialog.getInstance().updateImage(); 226 } else if (MapillaryData.getInstance().getHoveredImage() != closestTemp 227 && closestTemp == null) { 228 MapillaryData.getInstance().setHoveredImage(null); 229 MapillaryToggleDialog.getInstance().setImage( 230 MapillaryData.getInstance().getSelectedImage()); 231 MapillaryToggleDialog.getInstance().updateImage(); 232 } 233 MapillaryData.getInstance().dataUpdated(); 234 } 235 235 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillaryPlugin.java
r31277 r31278 31 31 public class MapillaryPlugin extends Plugin implements EditLayerChangeListener { 32 32 33 34 35 36 37 38 39 40 41 42 43 44 45 33 public static final ImageIcon ICON24 = new ImageProvider("icon24.png") 34 .get(); 35 public static final ImageIcon ICON16 = new ImageProvider("icon16.png") 36 .get(); 37 public static final ImageIcon MAP_ICON = new ImageProvider("mapicon.png") 38 .get(); 39 public static final ImageIcon MAP_ICON_SELECTED = new ImageProvider( 40 "mapiconselected.png").get(); 41 public static final ImageIcon MAP_ICON_IMPORTED = new ImageProvider( 42 "mapiconimported.png").get(); 43 public static final ImageIcon MAP_SIGN = new ImageProvider("sign.png") 44 .get(); 45 public static final int ICON_SIZE = 24; 46 46 47 47 public static CacheAccess<String, BufferedImageCacheEntry> CACHE; 48 48 49 50 51 52 53 54 49 private final MapillaryDownloadAction downloadAction; 50 private final MapillaryExportAction exportAction; 51 private final MapillaryImportAction importAction; 52 private final MapillarySignAction signAction; 53 private final MapillaryZoomAction zoomAction; 54 private final MapillaryDownloadViewAction downloadViewAction; 55 55 56 57 58 59 60 61 56 public static JMenuItem DOWNLOAD_MENU; 57 public static JMenuItem EXPORT_MENU; 58 public static JMenuItem IMPORT_MENU; 59 public static JMenuItem SIGN_MENU; 60 public static JMenuItem ZOOM_MENU; 61 public static JMenuItem DOWNLOAD_VIEW_MENU; 62 62 63 64 65 66 67 68 69 70 63 public MapillaryPlugin(PluginInformation info) { 64 super(info); 65 downloadAction = new MapillaryDownloadAction(); 66 exportAction = new MapillaryExportAction(); 67 importAction = new MapillaryImportAction(); 68 signAction = new MapillarySignAction(); 69 zoomAction = new MapillaryZoomAction(); 70 downloadViewAction = new MapillaryDownloadViewAction(); 71 71 72 DOWNLOAD_MENU = MainMenu.add(Main.main.menu.imageryMenu, 73 downloadAction, false); 74 EXPORT_MENU = MainMenu.add(Main.main.menu.fileMenu, exportAction, 75 false, 14); 76 IMPORT_MENU = MainMenu.add(Main.main.menu.fileMenu, importAction, 77 false, 14); 78 SIGN_MENU = MainMenu.add(Main.main.menu.dataMenu, signAction, false); 79 ZOOM_MENU = MainMenu 80 .add(Main.main.menu.viewMenu, zoomAction, false, 15); 81 DOWNLOAD_VIEW_MENU = MainMenu.add(Main.main.menu.fileMenu, 82 downloadViewAction, false, 14); 83 84 EXPORT_MENU.setEnabled(false); 85 DOWNLOAD_MENU.setEnabled(false); 86 IMPORT_MENU.setEnabled(false); 87 SIGN_MENU.setEnabled(false); 88 ZOOM_MENU.setEnabled(false); 89 DOWNLOAD_VIEW_MENU.setEnabled(false); 72 DOWNLOAD_MENU = MainMenu.add(Main.main.menu.imageryMenu, 73 downloadAction, false); 74 EXPORT_MENU = MainMenu.add(Main.main.menu.fileMenu, exportAction, 75 false, 14); 76 IMPORT_MENU = MainMenu.add(Main.main.menu.fileMenu, importAction, 77 false, 14); 78 SIGN_MENU = MainMenu.add(Main.main.menu.dataMenu, signAction, false); 79 ZOOM_MENU = MainMenu 80 .add(Main.main.menu.viewMenu, zoomAction, false, 15); 81 DOWNLOAD_VIEW_MENU = MainMenu.add(Main.main.menu.fileMenu, 82 downloadViewAction, false, 14); 90 83 91 MapView.addEditLayerChangeListener(this); 92 try { 93 CACHE = JCSCacheManager.getCache("mapillary", 10, 10000, 94 this.getPluginDir() + "/cache/"); 95 } catch (IOException e) { 96 Main.error(e); 97 } 98 } 84 EXPORT_MENU.setEnabled(false); 85 DOWNLOAD_MENU.setEnabled(false); 86 IMPORT_MENU.setEnabled(false); 87 SIGN_MENU.setEnabled(false); 88 ZOOM_MENU.setEnabled(false); 89 DOWNLOAD_VIEW_MENU.setEnabled(false); 99 90 100 /** 101 * Called when the JOSM map frame is created or destroyed. 102 */ 103 @Override 104 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { 105 if (oldFrame == null && newFrame != null) { // map frame added 106 } 107 if (oldFrame != null && newFrame == null) { // map frame destroyed 108 MapillaryToggleDialog.destroyInstance(); 109 } 110 } 91 MapView.addEditLayerChangeListener(this); 92 try { 93 CACHE = JCSCacheManager.getCache("mapillary", 10, 10000, 94 this.getPluginDir() + "/cache/"); 95 } catch (IOException e) { 96 Main.error(e); 97 } 98 } 111 99 112 public static void setMenuEnabled(JMenuItem menu, boolean value) { 113 menu.setEnabled(value); 114 } 100 /** 101 * Called when the JOSM map frame is created or destroyed. 102 */ 103 @Override 104 public void mapFrameInitialized(MapFrame oldFrame, MapFrame newFrame) { 105 if (oldFrame == null && newFrame != null) { // map frame added 106 } 107 if (oldFrame != null && newFrame == null) { // map frame destroyed 108 MapillaryToggleDialog.destroyInstance(); 109 } 110 } 115 111 116 @Override 117 public PreferenceSetting getPreferenceSetting() { 118 return new MapillaryPreferenceSetting(); 119 } 112 public static void setMenuEnabled(JMenuItem menu, boolean value) { 113 menu.setEnabled(value); 114 } 120 115 121 @Override 122 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) { 123 if (oldLayer == null && newLayer != null) { 124 DOWNLOAD_MENU.setEnabled(true); 125 IMPORT_MENU.setEnabled(true); 126 DOWNLOAD_VIEW_MENU.setEnabled(true); 127 } else if (oldLayer != null && newLayer == null) { 128 DOWNLOAD_MENU.setEnabled(false); 129 IMPORT_MENU.setEnabled(false); 130 DOWNLOAD_VIEW_MENU.setEnabled(false); 131 } 132 } 116 @Override 117 public PreferenceSetting getPreferenceSetting() { 118 return new MapillaryPreferenceSetting(); 119 } 120 121 @Override 122 public void editLayerChanged(OsmDataLayer oldLayer, OsmDataLayer newLayer) { 123 if (oldLayer == null && newLayer != null) { 124 DOWNLOAD_MENU.setEnabled(true); 125 IMPORT_MENU.setEnabled(true); 126 DOWNLOAD_VIEW_MENU.setEnabled(true); 127 } else if (oldLayer != null && newLayer == null) { 128 DOWNLOAD_MENU.setEnabled(false); 129 IMPORT_MENU.setEnabled(false); 130 DOWNLOAD_VIEW_MENU.setEnabled(false); 131 } 132 } 133 133 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/MapillarySequence.java
r31277 r31278 12 12 */ 13 13 public class MapillarySequence { 14 15 16 14 private final List<MapillaryImage> images; 15 private final String key; 16 private final long created_at; 17 17 18 19 20 21 22 18 public MapillarySequence(String key, long created_at) { 19 this.images = new ArrayList<>(); 20 this.key = key; 21 this.created_at = created_at; 22 } 23 23 24 25 26 27 28 29 30 31 24 /** 25 * Returns all MapillaryImages objects contained by this object. 26 * 27 * @return 28 */ 29 public List<MapillaryImage> getImages() { 30 return this.images; 31 } 32 32 33 34 35 33 public long getCreatedAt() { 34 return created_at; 35 } 36 36 37 38 39 40 41 42 43 44 37 /** 38 * Adds a new MapillaryImage object to this object. 39 * 40 * @param image 41 */ 42 public synchronized void add(MapillaryImage image) { 43 this.images.add(image); 44 } 45 45 46 47 48 46 public String getKey() { 47 return this.key; 48 } 49 49 50 51 52 53 54 55 56 57 58 50 /** 51 * Adds a set of MapillaryImage objects to this object. 52 * 53 * @param images 54 */ 55 public synchronized void add(List<MapillaryImage> images) { 56 for (MapillaryImage image : images) 57 add(image); 58 } 59 59 60 61 62 63 64 65 66 67 60 /** 61 * Removes a MapillaryImage object from this object. 62 * 63 * @param image 64 */ 65 public void remove(MapillaryImage image) { 66 this.images.remove(image); 67 } 68 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 69 /** 70 * Returns the next MapillaryImage in the sequence. 71 * 72 * @param image 73 * @return 74 */ 75 public MapillaryImage next(MapillaryImage image) { 76 if (!images.contains(image)) 77 throw new IllegalArgumentException(); 78 int i = images.indexOf(image); 79 if (i == images.size() - 1) 80 return null; 81 else 82 return images.get(i + 1); 83 } 84 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 85 /** 86 * Returns the previous MapillaryImage in the sequence. 87 * 88 * @param image 89 * @return 90 */ 91 public MapillaryImage previous(MapillaryImage image) { 92 if (!images.contains(image)) 93 throw new IllegalArgumentException(); 94 int i = images.indexOf(image); 95 if (i == 0) 96 return null; 97 else 98 return images.get(i - 1); 99 } 100 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 101 /** 102 * Returns the difference of index between two MapillaryImage objects 103 * belonging to the same MapillarySequence. 104 * 105 * @param image1 106 * @param image2 107 * @return 108 */ 109 public int getDistance(MapillaryImage image1, MapillaryImage image2) { 110 if (!this.images.contains(image1) || !this.images.contains(image2)) 111 throw new IllegalArgumentException(); 112 return Math.abs(this.images.indexOf(image1) 113 - this.images.indexOf(image2)); 114 } 115 115 116 117 118 119 120 121 116 @Override 117 public boolean equals(Object obj) { 118 if (obj instanceof MapillarySequence) 119 return this.getKey().equals(((MapillarySequence) obj).getKey()); 120 return false; 121 } 122 122 123 124 125 126 123 @Override 124 public int hashCode() { 125 return this.key.hashCode(); 126 } 127 127 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryDownloadAction.java
r31277 r31278 23 23 public class MapillaryDownloadAction extends JosmAction { 24 24 25 26 27 28 29 30 31 32 25 public MapillaryDownloadAction() { 26 super(tr("Mapillary"), new ImageProvider("icon24.png"), 27 tr("Create Mapillary layer"), Shortcut.registerShortcut( 28 "Mapillary", tr("Start Mapillary layer"), 29 KeyEvent.VK_M, Shortcut.ALT_CTRL_SHIFT), false, 30 "mapillaryDownload", false); 31 this.setEnabled(false); 32 } 33 33 34 35 36 37 38 39 40 41 42 43 44 45 46 34 @Override 35 public void actionPerformed(ActionEvent arg0) { 36 if (MapillaryLayer.INSTANCE == null) 37 MapillaryLayer.getInstance().download(); 38 else { 39 if (Main.map.mapView.getActiveLayer() != MapillaryLayer 40 .getInstance()) 41 Main.map.mapView.setActiveLayer(MapillaryLayer.getInstance()); 42 else 43 Main.map.mapView 44 .setActiveLayer(Main.map.mapView.getEditLayer()); 45 } 46 } 47 47 48 48 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryDownloadViewAction.java
r31277 r31278 17 17 public class MapillaryDownloadViewAction extends JosmAction { 18 18 19 20 19 public static double MAX_AREA = Main.pref.getDouble( 20 "mapillary.max-download-area", 0.025); 21 21 22 23 24 25 26 27 28 29 30 31 22 public MapillaryDownloadViewAction() { 23 super(tr("Download Mapillary images in current view"), 24 new ImageProvider("icon24.png"), 25 tr("Download Mapillary images in current view"), 26 Shortcut.registerShortcut("Mapillary area", 27 tr("Download Mapillary images in current view"), 28 KeyEvent.VK_M, Shortcut.NONE), false, "mapillaryArea", 29 false); 30 this.setEnabled(false); 31 } 32 32 33 34 35 36 37 38 39 40 41 42 43 44 45 33 @Override 34 public void actionPerformed(ActionEvent arg0) { 35 MapillaryLayer.getInstance(); 36 MapillaryLayer.getInstance().bounds.add(Main.map.mapView 37 .getRealBounds()); 38 if (Main.map.mapView.getRealBounds().getArea() <= MAX_AREA) { 39 new MapillaryDownloader().getImages(Main.map.mapView 40 .getRealBounds()); 41 } else { 42 JOptionPane.showMessageDialog(Main.parent, 43 tr("This area too big to be downloaded")); 44 } 45 } 46 46 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryExportAction.java
r31266 r31278 32 32 public class MapillaryExportAction extends JosmAction { 33 33 34 34 MapillaryExportDialog dialog; 35 35 36 public MapillaryExportAction() { 37 super(tr("Export pictures"), new ImageProvider("icon24.png"), 38 tr("Export pictures"), Shortcut.registerShortcut( 39 "Export Mapillary", tr("Export Mapillary pictures"), 40 KeyEvent.VK_M, Shortcut.NONE), false, "mapillaryExport", false); 41 this.setEnabled(false); 42 } 36 public MapillaryExportAction() { 37 super(tr("Export pictures"), new ImageProvider("icon24.png"), 38 tr("Export pictures"), Shortcut.registerShortcut( 39 "Export Mapillary", tr("Export Mapillary pictures"), 40 KeyEvent.VK_M, Shortcut.NONE), false, 41 "mapillaryExport", false); 42 this.setEnabled(false); 43 } 43 44 44 45 46 47 48 49 50 51 45 @Override 46 public void actionPerformed(ActionEvent e) { 47 dialog = new MapillaryExportDialog(); 48 JOptionPane pane = new JOptionPane(dialog, JOptionPane.PLAIN_MESSAGE, 49 JOptionPane.OK_CANCEL_OPTION); 50 JDialog dlg = pane.createDialog(Main.parent, tr("Export images")); 51 dlg.setMinimumSize(new Dimension(400, 150)); 52 dlg.setVisible(true); 52 53 53 // Checks if the inputs are correct and starts the export process. 54 if (pane.getValue() != null 55 && (int) pane.getValue() == JOptionPane.OK_OPTION 56 && dialog.chooser != null) { 57 if (dialog.group.isSelected(dialog.all.getModel())) { 58 export(MapillaryData.getInstance().getImages()); 59 } else if (dialog.group.isSelected(dialog.sequence.getModel())) { 60 ArrayList<MapillaryAbstractImage> images = new ArrayList<>(); 61 for (MapillaryAbstractImage image : MapillaryData.getInstance().getMultiSelectedImages()) 62 if (image instanceof MapillaryImage) { 63 if (!images.contains(image)) 64 images.addAll(((MapillaryImage) image).getSequence().getImages()); 65 } 66 else 67 images.add(image); 68 export(images); 69 } else if (dialog.group.isSelected(dialog.selected.getModel())) { 70 export(MapillaryData.getInstance().getMultiSelectedImages()); 71 } 72 // This option ignores the selected directory. 73 } else if (dialog.group.isSelected(dialog.rewrite.getModel())) { 74 ArrayList<MapillaryImportedImage> images = new ArrayList<>(); 75 for (MapillaryAbstractImage image : MapillaryData.getInstance().getImages()) 76 if (image instanceof MapillaryImportedImage) { 77 images.add(((MapillaryImportedImage) image)); 78 } 79 try { 80 Main.worker.submit(new Thread(new MapillaryExportManager(images))); 81 } catch (IOException e1) { 82 Main.error(e1); 83 } 84 } 85 dlg.dispose(); 86 } 54 // Checks if the inputs are correct and starts the export process. 55 if (pane.getValue() != null 56 && (int) pane.getValue() == JOptionPane.OK_OPTION 57 && dialog.chooser != null) { 58 if (dialog.group.isSelected(dialog.all.getModel())) { 59 export(MapillaryData.getInstance().getImages()); 60 } else if (dialog.group.isSelected(dialog.sequence.getModel())) { 61 ArrayList<MapillaryAbstractImage> images = new ArrayList<>(); 62 for (MapillaryAbstractImage image : MapillaryData.getInstance() 63 .getMultiSelectedImages()) 64 if (image instanceof MapillaryImage) { 65 if (!images.contains(image)) 66 images.addAll(((MapillaryImage) image) 67 .getSequence().getImages()); 68 } else 69 images.add(image); 70 export(images); 71 } else if (dialog.group.isSelected(dialog.selected.getModel())) { 72 export(MapillaryData.getInstance().getMultiSelectedImages()); 73 } 74 // This option ignores the selected directory. 75 } else if (dialog.group.isSelected(dialog.rewrite.getModel())) { 76 ArrayList<MapillaryImportedImage> images = new ArrayList<>(); 77 for (MapillaryAbstractImage image : MapillaryData.getInstance() 78 .getImages()) 79 if (image instanceof MapillaryImportedImage) { 80 images.add(((MapillaryImportedImage) image)); 81 } 82 try { 83 Main.worker.submit(new Thread( 84 new MapillaryExportManager(images))); 85 } catch (IOException e1) { 86 Main.error(e1); 87 } 88 } 89 dlg.dispose(); 90 } 87 91 88 89 90 91 92 93 94 92 /** 93 * Exports the given images from the database. 94 */ 95 public void export(List<MapillaryAbstractImage> images) { 96 Main.worker.submit(new Thread(new MapillaryExportManager(images, 97 dialog.chooser.getSelectedFile().toString()))); 98 } 95 99 96 100 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryImportAction.java
r31277 r31278 38 38 public class MapillaryImportAction extends JosmAction { 39 39 40 40 public JFileChooser chooser; 41 41 42 43 44 45 42 /** 43 * Amount of pictures without the proper EXIF tags. 44 */ 45 private int noTagsPics = 0; 46 46 47 48 49 50 51 52 53 54 55 47 public MapillaryImportAction() { 48 super(tr("Import pictures"), new ImageProvider("icon24.png"), 49 tr("Import local pictures"), Shortcut.registerShortcut( 50 "Import Mapillary", 51 tr("Import pictures into Mapillary layer"), 52 KeyEvent.VK_M, Shortcut.NONE), false, 53 "mapillaryImport", false); 54 this.setEnabled(false); 55 } 56 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 57 @Override 58 public void actionPerformed(ActionEvent e) { 59 chooser = new JFileChooser(); 60 chooser.setCurrentDirectory(new java.io.File(System 61 .getProperty("user.home"))); 62 chooser.setDialogTitle(tr("Select pictures")); 63 chooser.setFileSelectionMode(JFileChooser.FILES_AND_DIRECTORIES); 64 chooser.setAcceptAllFileFilterUsed(false); 65 chooser.addChoosableFileFilter(new FileNameExtensionFilter("images", 66 "jpg", "jpeg", "png")); 67 chooser.setMultiSelectionEnabled(true); 68 if (chooser.showOpenDialog(Main.parent) == JFileChooser.APPROVE_OPTION) { 69 for (int i = 0; i < chooser.getSelectedFiles().length; i++) { 70 File file = chooser.getSelectedFiles()[i]; 71 if (file.isDirectory()) { 72 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 73 } else { 74 if (file.getPath().substring(file.getPath().length() - 4) 75 .equals(".jpg") 76 || file.getPath() 77 .substring(file.getPath().length() - 5) 78 .equals(".jpeg")) { 79 try { 80 readJPG(file); 81 } catch (ImageReadException ex) { 82 Main.error(ex); 83 } catch (IOException ex) { 84 Main.error(ex); 85 } 86 } else if (file.getPath() 87 .substring(file.getPath().length() - 4) 88 .equals(".png")) { 89 readPNG(file); 90 } 91 } 92 } 93 } 94 MapillaryLayer.getInstance(); 95 } 96 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 97 /** 98 * Reads a jpg pictures that contains the needed GPS information (position 99 * and direction) and creates a new icon in that position. 100 * 101 * @param file 102 * @throws ImageReadException 103 * @throws IOException 104 */ 105 public void readJPG(File file) throws ImageReadException, IOException { 106 final ImageMetadata metadata = Imaging.getMetadata(file); 107 if (metadata instanceof JpegImageMetadata) { 108 final JpegImageMetadata jpegMetadata = (JpegImageMetadata) metadata; 109 final TiffField lat_ref = jpegMetadata 110 .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE_REF); 111 final TiffField lat = jpegMetadata 112 .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LATITUDE); 113 final TiffField lon_ref = jpegMetadata 114 .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE_REF); 115 final TiffField lon = jpegMetadata 116 .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_LONGITUDE); 117 final TiffField ca = jpegMetadata 118 .findEXIFValueWithExactMatch(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION); 119 final TiffField datetimeOriginal = jpegMetadata 120 .findEXIFValueWithExactMatch(ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL); 121 if (lat_ref == null || lat == null || lon == null 122 || lon_ref == null) { 123 readNoTags(file); 124 } 125 double latValue = 0; 126 double lonValue = 0; 127 double caValue = 0; 128 if (lat != null && lat.getValue() instanceof RationalNumber[]) 129 latValue = DegMinSecToDouble((RationalNumber[]) lat.getValue(), 130 lat_ref.getValue().toString()); 131 if (lon != null && lon.getValue() instanceof RationalNumber[]) 132 lonValue = DegMinSecToDouble((RationalNumber[]) lon.getValue(), 133 lon_ref.getValue().toString()); 134 if (ca != null && ca.getValue() instanceof RationalNumber) 135 caValue = ((RationalNumber) ca.getValue()).doubleValue(); 136 if (lat_ref.getValue().toString().equals("S")) 137 latValue = -latValue; 138 if (lon_ref.getValue().toString().equals("W")) 139 lonValue = -lonValue; 140 if (datetimeOriginal != null) 141 MapillaryData.getInstance().add( 142 new MapillaryImportedImage(latValue, lonValue, caValue, 143 file, datetimeOriginal.getStringValue())); 144 else 145 MapillaryData.getInstance().add( 146 new MapillaryImportedImage(latValue, lonValue, caValue, 147 file, currentDate())); 148 } 149 } 150 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 151 /** 152 * Reads a image file that doesn't contain the needed GPS information. And 153 * creates a new icon in the middle of the map. 154 * 155 * @param file 156 */ 157 private void readNoTags(File file) { 158 double HORIZONTAL_DISTANCE = 0.0001; 159 double horDev; 160 if (noTagsPics % 2 == 0) 161 horDev = HORIZONTAL_DISTANCE * noTagsPics / 2; 162 else 163 horDev = -HORIZONTAL_DISTANCE * (noTagsPics + 1) / 2; 164 LatLon pos = Main.map.mapView.getProjection().eastNorth2latlon( 165 Main.map.mapView.getCenter()); 166 MapillaryData.getInstance().add( 167 new MapillaryImportedImage(pos.lat(), pos.lon() + horDev, 0, 168 file, currentDate())); 169 noTagsPics++; 170 } 171 171 172 173 174 172 private void readPNG(File file) { 173 readNoTags(file); 174 } 175 175 176 private double DegMinSecToDouble(RationalNumber[] degMinSec, String ref) { 177 RationalNumber deg = degMinSec[0]; 178 RationalNumber min = degMinSec[1]; 179 RationalNumber sec = degMinSec[2]; 180 return deg.doubleValue() + min.doubleValue() / 60 + sec.doubleValue() 181 / 3600; 182 } 183 184 private String currentDate() { 185 Calendar cal = Calendar.getInstance(); 176 private double DegMinSecToDouble(RationalNumber[] degMinSec, String ref) { 177 RationalNumber deg = degMinSec[0]; 178 RationalNumber min = degMinSec[1]; 179 RationalNumber sec = degMinSec[2]; 180 return deg.doubleValue() + min.doubleValue() / 60 + sec.doubleValue() 181 / 3600; 182 } 186 183 187 SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss"); 188 return formatter.format(cal); 189 190 } 184 private String currentDate() { 185 Calendar cal = Calendar.getInstance(); 186 187 SimpleDateFormat formatter = new SimpleDateFormat("yyyy/MM/dd hh:mm:ss"); 188 return formatter.format(cal); 189 190 } 191 191 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillarySignAction.java
r31275 r31278 20 20 public class MapillarySignAction extends JosmAction { 21 21 22 public MapillarySignAction() { 23 super(tr("Switch sign/normal mode"), new ImageProvider("icon24sign.png"), 24 tr("Switch sign/normal mode"), Shortcut.registerShortcut( 25 "Mapillary sign", tr("Switch Mapillary plugin's sign mode on/off"), 26 KeyEvent.VK_M, Shortcut.NONE), false, 27 "mapillarySign", false); 28 this.setEnabled(false); 29 } 22 public MapillarySignAction() { 23 super(tr("Switch sign/normal mode"), 24 new ImageProvider("icon24sign.png"), 25 tr("Switch sign/normal mode"), Shortcut.registerShortcut( 26 "Mapillary sign", 27 tr("Switch Mapillary plugin's sign mode on/off"), 28 KeyEvent.VK_M, Shortcut.NONE), false, "mapillarySign", 29 false); 30 this.setEnabled(false); 31 } 30 32 31 32 33 34 33 @Override 34 public void actionPerformed(ActionEvent e) { 35 MapillaryToggleDialog.getInstance().switchMode(); 36 } 35 37 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/actions/MapillaryZoomAction.java
r31266 r31278 22 22 */ 23 23 public class MapillaryZoomAction extends JosmAction implements 24 24 MapillaryDataListener { 25 25 26 27 28 29 30 31 32 33 34 35 26 public MapillaryZoomAction() { 27 super(tr("Zoom to selected image"), new ImageProvider("icon24.png"), 28 tr("Zoom to selected image"), Shortcut.registerShortcut( 29 "Zoom Mapillary", 30 tr("Zoom to the currently selected Mapillary image"), 31 KeyEvent.VK_M, Shortcut.NONE), false, "mapillaryZoom", 32 false); 33 MapillaryData.getInstance().addListener(this); 34 this.setEnabled(false); 35 } 36 36 37 38 39 40 41 42 43 37 @Override 38 public void actionPerformed(ActionEvent arg0) { 39 if (MapillaryData.getInstance().getSelectedImage() == null) 40 throw new IllegalStateException(); 41 Main.map.mapView.zoomTo(MapillaryData.getInstance().getSelectedImage() 42 .getLatLon()); 43 } 44 44 45 46 47 48 49 50 51 52 45 @Override 46 public void selectedImageChanged(MapillaryAbstractImage oldImage, 47 MapillaryAbstractImage newImage) { 48 if (oldImage == null && newImage != null) 49 MapillaryPlugin.ZOOM_MENU.setEnabled(true); 50 else if (oldImage != null && newImage == null) 51 MapillaryPlugin.ZOOM_MENU.setEnabled(false); 52 } 53 53 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/cache/MapillaryCache.java
r31273 r31278 11 11 12 12 public class MapillaryCache extends 13 13 JCSCachedTileLoaderJob<String, BufferedImageCacheEntry> { 14 14 15 16 15 private volatile URL url; 16 private volatile String key; 17 17 18 19 20 18 public static enum Type { 19 FULL_IMAGE, THUMBNAIL 20 } 21 21 22 public MapillaryCache(String key, Type type) { 23 super(MapillaryPlugin.CACHE, 50000, 50000, new HashMap<String, String>()); 24 this.key = key; 25 try { 26 if (type == Type.FULL_IMAGE) { 27 url = new URL("https://d1cuyjsrcm0gby.cloudfront.net/" + key 28 + "/thumb-2048.jpg"); 29 this.key += ".FULL_IMAGE"; 22 public MapillaryCache(String key, Type type) { 23 super(MapillaryPlugin.CACHE, 50000, 50000, 24 new HashMap<String, String>()); 25 this.key = key; 26 try { 27 if (type == Type.FULL_IMAGE) { 28 url = new URL("https://d1cuyjsrcm0gby.cloudfront.net/" + key 29 + "/thumb-2048.jpg"); 30 this.key += ".FULL_IMAGE"; 30 31 31 32 33 34 35 36 37 38 39 32 } else if (type == Type.THUMBNAIL) { 33 url = new URL("https://d1cuyjsrcm0gby.cloudfront.net/" + key 34 + "/thumb-320.jpg"); 35 this.key += ".THUMBNAIL"; 36 } 37 } catch (MalformedURLException e) { 38 Main.error(e); 39 } 40 } 40 41 41 42 43 44 42 @Override 43 public String getCacheKey() { 44 return key; 45 } 45 46 46 47 48 49 47 @Override 48 public URL getUrl() { 49 return url; 50 } 50 51 51 52 53 54 52 @Override 53 protected BufferedImageCacheEntry createCacheEntry(byte[] content) { 54 return new BufferedImageCacheEntry(content); 55 } 55 56 56 57 58 59 60 61 62 57 @Override 58 protected boolean isObjectLoadable() { 59 if (cacheData == null) 60 return false; 61 byte[] content = cacheData.getContent(); 62 return content != null && content.length > 0; 63 } 63 64 64 65 66 67 65 // @Override 66 protected boolean handleNotFound() { 67 return false; 68 } 68 69 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandMoveImage.java
r31257 r31278 16 16 */ 17 17 public class CommandMoveImage extends MapillaryCommand { 18 19 18 private double x; 19 private double y; 20 20 21 public CommandMoveImage(List<MapillaryAbstractImage> images, double x, double y) { 22 this.images = new ArrayList<>(images); 23 this.x = x; 24 this.y = y; 25 } 21 public CommandMoveImage(List<MapillaryAbstractImage> images, double x, 22 double y) { 23 this.images = new ArrayList<>(images); 24 this.x = x; 25 this.y = y; 26 } 26 27 27 28 29 30 31 32 33 34 35 28 @Override 29 public void undo() { 30 for (MapillaryAbstractImage image : images) { 31 image.move(-x, -y); 32 image.stopMoving(); 33 } 34 checkModified(); 35 Main.map.repaint(); 36 } 36 37 37 @Override 38 public void redo() { 39 for (MapillaryAbstractImage image : images) { 40 image.move(x, y); 41 image.stopMoving(); 42 } 43 checkModified(); 44 Main.map.repaint(); 45 } 46 47 public String toString() { 48 return trn("Moved {0} node", "Moved {0} nodes", images.size(), images.size()); 49 } 50 51 @Override 52 public void sum(MapillaryCommand command) { 53 if (command instanceof CommandMoveImage) { 54 this.x += ((CommandMoveImage) command).x; 55 this.y += ((CommandMoveImage) command).y; 56 } 57 } 38 @Override 39 public void redo() { 40 for (MapillaryAbstractImage image : images) { 41 image.move(x, y); 42 image.stopMoving(); 43 } 44 checkModified(); 45 Main.map.repaint(); 46 } 47 48 public String toString() { 49 return trn("Moved {0} node", "Moved {0} nodes", images.size(), 50 images.size()); 51 } 52 53 @Override 54 public void sum(MapillaryCommand command) { 55 if (command instanceof CommandMoveImage) { 56 this.x += ((CommandMoveImage) command).x; 57 this.y += ((CommandMoveImage) command).y; 58 } 59 } 58 60 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/CommandTurnImage.java
r31257 r31278 16 16 */ 17 17 public class CommandTurnImage extends MapillaryCommand { 18 18 private double ca; 19 19 20 21 22 23 20 public CommandTurnImage(List<MapillaryAbstractImage> images, double ca) { 21 this.images = new ArrayList<>(images); 22 this.ca = ca; 23 } 24 24 25 26 27 28 29 30 31 32 33 25 @Override 26 public void undo() { 27 for (MapillaryAbstractImage image : images) { 28 image.turn(-ca); 29 image.stopMoving(); 30 } 31 checkModified(); 32 Main.map.repaint(); 33 } 34 34 35 36 37 38 39 40 41 42 43 35 @Override 36 public void redo() { 37 for (MapillaryAbstractImage image : images) { 38 image.turn(ca); 39 image.stopMoving(); 40 } 41 checkModified(); 42 Main.map.repaint(); 43 } 44 44 45 46 47 48 45 public String toString() { 46 return trn("Turned {0} node", "Turned {0} nodes", this.images.size(), 47 this.images.size()); 48 } 49 49 50 51 52 53 54 55 50 @Override 51 public void sum(MapillaryCommand command) { 52 if (command instanceof CommandTurnImage) { 53 this.ca += ((CommandTurnImage) command).ca; 54 } 55 } 56 56 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/MapillaryCommand.java
r31264 r31278 12 12 */ 13 13 public abstract class MapillaryCommand { 14 14 protected List<MapillaryAbstractImage> images; 15 15 16 16 public abstract void undo(); 17 17 18 18 public abstract void redo(); 19 19 20 21 22 23 24 25 26 20 /** 21 * If two equal commands are applied consecutively to the same set of 22 * images, they are summed in order to reduce them to just one command. 23 * 24 * @param command 25 */ 26 public abstract void sum(MapillaryCommand command); 27 27 28 29 30 31 32 33 34 35 28 /** 29 * Checks if the image has been modified, compairing with its original 30 * values. 31 */ 32 public void checkModified() { 33 for (MapillaryAbstractImage image : images) 34 image.isModified = (image.tempLatLon == image.latLon || image.tempCa == image.ca); 35 } 36 36 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/MapillaryRecord.java
r31257 r31278 10 10 */ 11 11 public class MapillaryRecord { 12 12 public static MapillaryRecord INSTANCE; 13 13 14 14 private ArrayList<MapillaryRecordListener> listeners; 15 15 16 17 18 16 public ArrayList<MapillaryCommand> commandList; 17 /** Last written command */ 18 public int position; 19 19 20 21 22 23 24 20 public MapillaryRecord() { 21 commandList = new ArrayList<>(); 22 position = -1; 23 listeners = new ArrayList<>(); 24 } 25 25 26 27 28 29 30 26 public static synchronized MapillaryRecord getInstance() { 27 if (MapillaryRecord.INSTANCE == null) 28 MapillaryRecord.INSTANCE = new MapillaryRecord(); 29 return MapillaryRecord.INSTANCE; 30 } 31 31 32 33 34 32 public void addListener(MapillaryRecordListener lis) { 33 this.listeners.add(lis); 34 } 35 35 36 37 38 36 public void removeListener(MapillaryRecordListener lis) { 37 this.listeners.remove(lis); 38 } 39 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 40 /** 41 * Adds a new command to the list. 42 * 43 * @param command 44 */ 45 public void addCommand(MapillaryCommand command) { 46 // Checks if it is a continuation of last command 47 if (position != -1 48 && commandList.get(position).images.equals(command.images) 49 && commandList.get(position).getClass() == command.getClass()) { 50 commandList.get(position).sum(command); 51 fireRecordChanged(); 52 return; 53 } 54 commandList.add(position + 1, command); 55 position++; 56 while (commandList.size() > position + 1) { 57 commandList.remove(position + 1); 58 } 59 fireRecordChanged(); 60 } 61 61 62 63 64 65 66 67 68 69 70 71 62 /** 63 * Undo latest command. 64 */ 65 public void undo() { 66 if (position == -1) 67 return; 68 commandList.get(position).undo(); 69 position--; 70 fireRecordChanged(); 71 } 72 72 73 74 75 76 77 78 79 80 81 82 73 /** 74 * Redo latest undoed action. 75 */ 76 public void redo() { 77 if (position + 1 >= commandList.size()) 78 return; 79 position++; 80 commandList.get(position).redo(); 81 fireRecordChanged(); 82 } 83 83 84 85 86 87 88 84 private void fireRecordChanged() { 85 for (MapillaryRecordListener lis : listeners) 86 if (lis != null) 87 lis.recordChanged(); 88 } 89 89 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/commands/MapillaryRecordListener.java
r31257 r31278 2 2 3 3 public interface MapillaryRecordListener { 4 4 public void recordChanged(); 5 5 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryDownloader.java
r31277 r31278 15 15 public class MapillaryDownloader { 16 16 17 18 17 public final static String BASE_URL = "https://a.mapillary.com/v2/"; 18 public final static String CLIENT_ID = "NzNRM2otQkR2SHJzaXJmNmdQWVQ0dzo1YTA2NmNlODhlNWMwOTBm"; 19 19 20 21 20 private String[] parameters = { "lat", "lon", "distance", "limit", 21 "min_lat", "min_lon", "max_lat", "max_lon" }; 22 22 23 24 23 public MapillaryDownloader() { 24 } 25 25 26 /** 27 * Gets all the images in a square. It downloads all the images of all the 28 * sequences that pass through the given rectangle. 29 * 30 * @param minLatLon 31 * The minimum latitude and longitude of the rectangle. 32 * @param maxLatLon 33 * The maximum latitude and longitude of the rectangle 34 */ 35 public void getImages(LatLon minLatLon, LatLon maxLatLon) { 36 String url1 = BASE_URL; 37 String url2 = BASE_URL; 38 String url3 = BASE_URL; 39 url1 += "search/im/"; 40 url2 += "search/s/"; 41 url3 += "search/im/or"; 42 ConcurrentHashMap<String, Double> hash = new ConcurrentHashMap<>(); 43 hash.put("min_lat", minLatLon.lat()); 44 hash.put("min_lon", minLatLon.lon()); 45 hash.put("max_lat", maxLatLon.lat()); 46 hash.put("max_lon", maxLatLon.lon()); 47 url1 += buildParameters(hash); 48 url2 += buildParameters(hash); 49 url3 += buildParameters(hash); 50 System.out.println(url2); 51 52 try { 53 Main.info("MapillaryPlugin GET " + url2); 54 Main.worker.submit(new MapillarySquareDownloadManagerThread(url1, url2, url3)); 55 } catch (Exception e) { 56 Main.error(e); 57 } 58 } 59 60 public void getImages(Bounds bounds) { 61 getImages(bounds.getMin(), bounds.getMax()); 62 } 26 /** 27 * Gets all the images in a square. It downloads all the images of all the 28 * sequences that pass through the given rectangle. 29 * 30 * @param minLatLon 31 * The minimum latitude and longitude of the rectangle. 32 * @param maxLatLon 33 * The maximum latitude and longitude of the rectangle 34 */ 35 public void getImages(LatLon minLatLon, LatLon maxLatLon) { 36 String url1 = BASE_URL; 37 String url2 = BASE_URL; 38 String url3 = BASE_URL; 39 url1 += "search/im/"; 40 url2 += "search/s/"; 41 url3 += "search/im/or"; 42 ConcurrentHashMap<String, Double> hash = new ConcurrentHashMap<>(); 43 hash.put("min_lat", minLatLon.lat()); 44 hash.put("min_lon", minLatLon.lon()); 45 hash.put("max_lat", maxLatLon.lat()); 46 hash.put("max_lon", maxLatLon.lon()); 47 url1 += buildParameters(hash); 48 url2 += buildParameters(hash); 49 url3 += buildParameters(hash); 50 System.out.println(url2); 63 51 64 private String buildParameters(ConcurrentHashMap<String, Double> hash) { 65 String ret = "?client_id=" + CLIENT_ID; 66 for (int i = 0; i < parameters.length; i++) 67 if (hash.get(parameters[i]) != null) 68 ret += "&" + parameters[i] + "=" + hash.get(parameters[i]); 69 return ret; 70 } 52 try { 53 Main.info("MapillaryPlugin GET " + url2); 54 Main.worker.submit(new MapillarySquareDownloadManagerThread(url1, 55 url2, url3)); 56 } catch (Exception e) { 57 Main.error(e); 58 } 59 } 60 61 public void getImages(Bounds bounds) { 62 getImages(bounds.getMin(), bounds.getMax()); 63 } 64 65 private String buildParameters(ConcurrentHashMap<String, Double> hash) { 66 String ret = "?client_id=" + CLIENT_ID; 67 for (int i = 0; i < parameters.length; i++) 68 if (hash.get(parameters[i]) != null) 69 ret += "&" + parameters[i] + "=" + hash.get(parameters[i]); 70 return ret; 71 } 71 72 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportDownloadThread.java
r31252 r31278 25 25 */ 26 26 public class MapillaryExportDownloadThread implements Runnable, 27 27 ICachedLoaderListener { 28 28 29 30 31 29 String url; 30 ArrayBlockingQueue<BufferedImage> queue; 31 ArrayBlockingQueue<MapillaryAbstractImage> queueImages; 32 32 33 34 33 ProgressMonitor monitor; 34 MapillaryImage image; 35 35 36 37 38 39 40 41 42 43 44 36 public MapillaryExportDownloadThread(MapillaryImage image, 37 ArrayBlockingQueue<BufferedImage> queue, 38 ArrayBlockingQueue<MapillaryAbstractImage> queueImages) { 39 url = "https://d1cuyjsrcm0gby.cloudfront.net/" + image.getKey() 40 + "/thumb-2048.jpg"; 41 this.queue = queue; 42 this.image = image; 43 this.queueImages = queueImages; 44 } 45 45 46 47 48 new MapillaryCache(image.getKey(), MapillaryCache.Type.FULL_IMAGE).submit(this, 49 46 @Override 47 public void run() { 48 new MapillaryCache(image.getKey(), MapillaryCache.Type.FULL_IMAGE) 49 .submit(this, false); 50 50 51 51 } 52 52 53 54 55 56 57 58 53 @Override 54 public void loadingFinished(CacheEntry data, 55 CacheEntryAttributes attributes, LoadResult result) { 56 try { 57 queue.put(ImageIO.read(new ByteArrayInputStream(data.getContent()))); 58 queueImages.put(image); 59 59 60 61 62 63 64 65 60 } catch (InterruptedException e) { 61 Main.error(e); 62 } catch (IOException e) { 63 Main.error(e); 64 } 65 } 66 66 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportManager.java
r31277 r31278 32 32 public class MapillaryExportManager extends PleaseWaitRunnable { 33 33 34 35 34 ArrayBlockingQueue<BufferedImage> queue; 35 ArrayBlockingQueue<MapillaryAbstractImage> queueImages; 36 36 37 38 39 37 final int amount; 38 List<MapillaryAbstractImage> images; 39 String path; 40 40 41 42 43 44 45 46 41 public MapillaryExportManager(List<MapillaryAbstractImage> images, 42 String path) { 43 super(tr("Downloading") + "...", new PleaseWaitProgressMonitor( 44 "Exporting Mapillary Images"), true); 45 queue = new ArrayBlockingQueue<>(10); 46 queueImages = new ArrayBlockingQueue<>(10); 47 47 48 this.images = images; 49 amount = images.size(); 50 this.path = path; 51 } 52 53 /** 54 * Constructor used to rewrite imported images. 55 * @param images 56 * @throws IOException 57 */ 58 public MapillaryExportManager(List<MapillaryImportedImage> images) throws IOException { 59 super(tr("Downloading") + "...", new PleaseWaitProgressMonitor( 60 "Exporting Mapillary Images"), true); 61 queue = new ArrayBlockingQueue<>(10); 62 queueImages = new ArrayBlockingQueue<>(10); 63 for (MapillaryImportedImage image : images) { 64 queue.add(image.getImage()); 65 queueImages.add(image); 66 } 67 amount = images.size(); 68 } 48 this.images = images; 49 amount = images.size(); 50 this.path = path; 51 } 69 52 70 @Override 71 protected void cancel() { 72 // TODO Auto-generated method stub 73 } 53 /** 54 * Constructor used to rewrite imported images. 55 * 56 * @param images 57 * @throws IOException 58 */ 59 public MapillaryExportManager(List<MapillaryImportedImage> images) 60 throws IOException { 61 super(tr("Downloading") + "...", new PleaseWaitProgressMonitor( 62 "Exporting Mapillary Images"), true); 63 queue = new ArrayBlockingQueue<>(10); 64 queueImages = new ArrayBlockingQueue<>(10); 65 for (MapillaryImportedImage image : images) { 66 queue.add(image.getImage()); 67 queueImages.add(image); 68 } 69 amount = images.size(); 70 } 74 71 75 @Override 76 protected void realRun() throws SAXException, IOException, 77 OsmTransferException { 78 // Starts a writer thread in order to write the pictures on the disk. 79 Thread writer = new Thread(new MapillaryExportWriterThread(path, queue, 80 queueImages, amount, this.getProgressMonitor())); 81 writer.start(); 82 if (path == null) { 83 try { 84 writer.join(); 85 } catch (InterruptedException e) { 86 Main.error(e); 87 } 88 return; 89 } 90 ThreadPoolExecutor ex = new ThreadPoolExecutor(20, 35, 25, 91 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); 92 for (MapillaryAbstractImage image : images) { 93 if (image instanceof MapillaryImage) { 94 try { 95 ex.execute(new MapillaryExportDownloadThread( 96 (MapillaryImage) image, queue, queueImages)); 97 } catch (Exception e) { 98 Main.error(e); 99 } 100 } else if (image instanceof MapillaryImportedImage) { 101 try { 102 queue.put(((MapillaryImportedImage) image).getImage()); 103 queueImages.put((MapillaryImportedImage) image); 104 } catch (InterruptedException e) { 105 Main.error(e); 106 } 107 } 108 try { 109 // If the queue is full, waits for it to have more space 110 // available before executing anything else. 111 while (ex.getQueue().remainingCapacity() == 0) 112 Thread.sleep(100); 113 } catch (Exception e) { 114 Main.error(e); 115 } 116 } 117 try { 118 writer.join(); 119 } catch (InterruptedException e) { 120 Main.error(e); 121 } 72 @Override 73 protected void cancel() { 74 // TODO Auto-generated method stub 75 } 122 76 123 } 77 @Override 78 protected void realRun() throws SAXException, IOException, 79 OsmTransferException { 80 // Starts a writer thread in order to write the pictures on the disk. 81 Thread writer = new Thread(new MapillaryExportWriterThread(path, queue, 82 queueImages, amount, this.getProgressMonitor())); 83 writer.start(); 84 if (path == null) { 85 try { 86 writer.join(); 87 } catch (InterruptedException e) { 88 Main.error(e); 89 } 90 return; 91 } 92 ThreadPoolExecutor ex = new ThreadPoolExecutor(20, 35, 25, 93 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(10)); 94 for (MapillaryAbstractImage image : images) { 95 if (image instanceof MapillaryImage) { 96 try { 97 ex.execute(new MapillaryExportDownloadThread( 98 (MapillaryImage) image, queue, queueImages)); 99 } catch (Exception e) { 100 Main.error(e); 101 } 102 } else if (image instanceof MapillaryImportedImage) { 103 try { 104 queue.put(((MapillaryImportedImage) image).getImage()); 105 queueImages.put((MapillaryImportedImage) image); 106 } catch (InterruptedException e) { 107 Main.error(e); 108 } 109 } 110 try { 111 // If the queue is full, waits for it to have more space 112 // available before executing anything else. 113 while (ex.getQueue().remainingCapacity() == 0) 114 Thread.sleep(100); 115 } catch (Exception e) { 116 Main.error(e); 117 } 118 } 119 try { 120 writer.join(); 121 } catch (InterruptedException e) { 122 Main.error(e); 123 } 124 124 125 @Override 126 protected void finish() { 127 // TODO Auto-generated method stub 128 } 125 } 126 127 @Override 128 protected void finish() { 129 // TODO Auto-generated method stub 130 } 129 131 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryExportWriterThread.java
r31277 r31278 34 34 public class MapillaryExportWriterThread implements Runnable { 35 35 36 37 38 39 40 36 private final String path; 37 private final ArrayBlockingQueue<BufferedImage> queue; 38 private final ArrayBlockingQueue<MapillaryAbstractImage> queueImages; 39 private final int amount; 40 private final ProgressMonitor monitor; 41 41 42 43 44 45 46 47 48 49 50 51 42 public MapillaryExportWriterThread(String path, 43 ArrayBlockingQueue<BufferedImage> queue, 44 ArrayBlockingQueue<MapillaryAbstractImage> queueImages, int amount, 45 ProgressMonitor monitor) { 46 this.path = path; 47 this.queue = queue; 48 this.queueImages = queueImages; 49 this.amount = amount; 50 this.monitor = monitor; 51 } 52 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 53 @Override 54 public void run() { 55 monitor.setCustomText("Downloaded 0/" + amount); 56 File tempFile = null; 57 BufferedImage img; 58 MapillaryAbstractImage mimg = null; 59 String finalPath = ""; 60 for (int i = 0; i < amount; i++) { 61 try { 62 img = queue.take(); 63 mimg = queueImages.take(); 64 if (path == null && mimg instanceof MapillaryImportedImage) { 65 String path = ((MapillaryImportedImage) mimg).getFile() 66 .getPath(); 67 finalPath = path.substring(0, path.lastIndexOf('.')); 68 } else if (mimg instanceof MapillaryImage) 69 finalPath = path + "/" + ((MapillaryImage) mimg).getKey(); 70 else 71 finalPath = path + "/" + i; 72 // Creates a temporal file that is going to be deleted after 73 // writing the EXIF tags. 74 tempFile = new File(finalPath + ".tmp"); 75 ImageIO.write(img, "jpg", tempFile); 76 76 77 // Write EXIF tags 78 TiffOutputSet outputSet = new TiffOutputSet(); 79 TiffOutputDirectory exifDirectory = outputSet.getOrCreateExifDirectory(); 80 exifDirectory 81 .add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF, 82 GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH); 83 exifDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, 84 RationalNumber.valueOf(mimg.getCa())); 85 if (mimg instanceof MapillaryImportedImage) { 86 exifDirectory.add( 87 ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, 88 ((MapillaryImportedImage) mimg).datetimeOriginal); 89 } 90 else if (mimg instanceof MapillaryImage) 91 exifDirectory.add( 92 ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, 93 ((MapillaryImage) mimg).getDate("yyyy/MM/dd hh/mm/ss")); 94 outputSet.setGPSInDegrees(mimg.getLatLon().lon(), mimg 95 .getLatLon().lat()); 96 OutputStream os = new BufferedOutputStream( 97 new FileOutputStream(finalPath + ".jpg")); 98 new ExifRewriter().updateExifMetadataLossless(tempFile, os, 99 outputSet); 100 tempFile.delete(); 101 os.close(); 102 } catch (InterruptedException e) { 103 Main.error(e); 104 } catch (IOException e) { 105 Main.error(e); 106 } catch (ImageWriteException e) { 107 Main.error(e); 108 } catch (ImageReadException e) { 109 Main.error(e); 110 } 77 // Write EXIF tags 78 TiffOutputSet outputSet = new TiffOutputSet(); 79 TiffOutputDirectory exifDirectory = outputSet 80 .getOrCreateExifDirectory(); 81 exifDirectory 82 .add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF, 83 GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION_REF_VALUE_TRUE_NORTH); 84 exifDirectory.add(GpsTagConstants.GPS_TAG_GPS_IMG_DIRECTION, 85 RationalNumber.valueOf(mimg.getCa())); 86 if (mimg instanceof MapillaryImportedImage) { 87 exifDirectory.add( 88 ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, 89 ((MapillaryImportedImage) mimg).datetimeOriginal); 90 } else if (mimg instanceof MapillaryImage) 91 exifDirectory.add( 92 ExifTagConstants.EXIF_TAG_DATE_TIME_ORIGINAL, 93 ((MapillaryImage) mimg) 94 .getDate("yyyy/MM/dd hh/mm/ss")); 95 outputSet.setGPSInDegrees(mimg.getLatLon().lon(), mimg 96 .getLatLon().lat()); 97 OutputStream os = new BufferedOutputStream( 98 new FileOutputStream(finalPath + ".jpg")); 99 new ExifRewriter().updateExifMetadataLossless(tempFile, os, 100 outputSet); 101 tempFile.delete(); 102 os.close(); 103 } catch (InterruptedException e) { 104 Main.error(e); 105 } catch (IOException e) { 106 Main.error(e); 107 } catch (ImageWriteException e) { 108 Main.error(e); 109 } catch (ImageReadException e) { 110 Main.error(e); 111 } 111 112 112 113 114 115 116 113 // Increases the progress bar. 114 monitor.worked(PleaseWaitProgressMonitor.PROGRESS_BAR_MAX / amount); 115 monitor.setCustomText("Downloaded " + (i + 1) + "/" + amount); 116 } 117 } 117 118 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillaryImageInfoDownloaderThread.java
r31267 r31278 25 25 */ 26 26 public class MapillaryImageInfoDownloaderThread implements Runnable { 27 28 27 private final String url; 28 private final ExecutorService ex; 29 29 30 31 32 33 30 public MapillaryImageInfoDownloaderThread(ExecutorService ex, String url) { 31 this.ex = ex; 32 this.url = url; 33 } 34 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 35 public void run() { 36 try { 37 BufferedReader br = new BufferedReader(new InputStreamReader( 38 new URL(url).openStream())); 39 JsonObject jsonobj = Json.createReader(br).readObject(); 40 if (!jsonobj.getBoolean("more")) 41 ex.shutdown(); 42 JsonArray jsonarr = jsonobj.getJsonArray("ims"); 43 JsonObject data; 44 for (int i = 0; i < jsonarr.size(); i++) { 45 data = jsonarr.getJsonObject(i); 46 String key = data.getString("key"); 47 for (MapillaryAbstractImage image : MapillaryData.getInstance() 48 .getImages()) { 49 if (image instanceof MapillaryImage) { 50 if (((MapillaryImage) image).getKey().equals(key)) { 51 ((MapillaryImage) image).setUser(data 52 .getString("user")); 53 ((MapillaryImage) image).setCapturedAt(data 54 .getJsonNumber("captured_at").longValue()); 55 ((MapillaryImage) image).setLocation(data 56 .getString("location")); 57 } 58 } 59 } 60 } 61 } catch (MalformedURLException e) { 62 Main.error(e); 63 } catch (IOException e) { 64 Main.error(e); 65 } 66 } 67 67 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySequenceDownloadThread.java
r31277 r31278 32 32 public class MapillarySequenceDownloadThread implements Runnable { 33 33 34 35 36 34 private String url; 35 private ExecutorService ex; 36 private List<Bounds> bounds; 37 37 38 39 40 41 42 38 public MapillarySequenceDownloadThread(ExecutorService ex, String url) { 39 this.url = url; 40 this.ex = ex; 41 this.bounds = MapillaryLayer.getInstance().bounds; 42 } 43 43 44 45 46 47 48 49 44 public void run() { 45 try { 46 BufferedReader br; 47 br = new BufferedReader(new InputStreamReader( 48 new URL(url).openStream())); 49 JsonObject jsonall = Json.createReader(br).readObject(); 50 50 51 if (!jsonall.getBoolean("more") && !ex.isShutdown()) 52 ex.shutdown(); 53 JsonArray jsonseq = jsonall.getJsonArray("ss"); 54 // At the moment there is a bug with some sequences at Mapillay API, 55 // so if they are wrong he use this variable to skip them. 56 boolean isSequenceWrong = false; 57 for (int i = 0; i < jsonseq.size(); i++) { 58 JsonObject jsonobj = jsonseq.getJsonObject(i); 59 JsonArray cas = jsonobj.getJsonArray("cas"); 60 JsonArray coords = jsonobj.getJsonArray("coords"); 61 JsonArray keys = jsonobj.getJsonArray("keys"); 62 ArrayList<MapillaryImage> images = new ArrayList<>(); 63 for (int j = 0; j < cas.size(); j++) { 64 try { 65 images.add(new MapillaryImage(keys.getString(j), 66 coords.getJsonArray(j).getJsonNumber(1) 67 .doubleValue(), coords.getJsonArray(j) 68 .getJsonNumber(0).doubleValue(), cas 69 .getJsonNumber(j).doubleValue())); 70 } catch (IndexOutOfBoundsException e) { 71 Main.warn("Mapillary bug at " + url); 72 isSequenceWrong = true; 73 } 74 } 75 if (isSequenceWrong) 76 break; 77 MapillarySequence sequence = new MapillarySequence( 78 jsonobj.getString("key"), jsonobj.getJsonNumber( 79 "captured_at").longValue()); 80 81 int first = -1; 82 int last = -1; 83 int pos = 0; 51 if (!jsonall.getBoolean("more") && !ex.isShutdown()) 52 ex.shutdown(); 53 JsonArray jsonseq = jsonall.getJsonArray("ss"); 54 // At the moment there is a bug with some sequences at Mapillay API, 55 // so if they are wrong he use this variable to skip them. 56 boolean isSequenceWrong = false; 57 for (int i = 0; i < jsonseq.size(); i++) { 58 JsonObject jsonobj = jsonseq.getJsonObject(i); 59 JsonArray cas = jsonobj.getJsonArray("cas"); 60 JsonArray coords = jsonobj.getJsonArray("coords"); 61 JsonArray keys = jsonobj.getJsonArray("keys"); 62 ArrayList<MapillaryImage> images = new ArrayList<>(); 63 for (int j = 0; j < cas.size(); j++) { 64 try { 65 images.add(new MapillaryImage(keys.getString(j), 66 coords.getJsonArray(j).getJsonNumber(1) 67 .doubleValue(), coords.getJsonArray(j) 68 .getJsonNumber(0).doubleValue(), cas 69 .getJsonNumber(j).doubleValue())); 70 } catch (IndexOutOfBoundsException e) { 71 Main.warn("Mapillary bug at " + url); 72 isSequenceWrong = true; 73 } 74 } 75 if (isSequenceWrong) 76 break; 77 MapillarySequence sequence = new MapillarySequence( 78 jsonobj.getString("key"), jsonobj.getJsonNumber( 79 "captured_at").longValue()); 84 80 85 // Here it gets only those images which are in the downloaded 86 // area. 87 for (MapillaryAbstractImage img : images) { 88 if (first == -1 && isInside(img)) 89 first = pos; 90 else if (first != -1 && last == -1 91 && !isInside(img)) 92 last = pos; 93 else if (last != -1 && isInside(img)) 94 last = -1; 95 pos++; 96 } 97 if (last == -1) { 98 last = pos; 99 } 100 if (first == -1) 101 continue; 102 List<MapillaryImage> finalImages = images.subList(first, last); 103 for (MapillaryImage img : finalImages) { 104 MapillaryData.getInstance().getImages().remove(img); 105 img.setSequence(sequence); 106 } 107 MapillaryData.getInstance().addWithoutUpdate( 108 new ArrayList<MapillaryAbstractImage>(finalImages)); 109 sequence.add(finalImages); 110 } 111 } catch (IOException e) { 112 Main.error("Error reading the url " + url 113 + " might be a Mapillary problem."); 114 } 115 } 116 117 private boolean isInside(MapillaryAbstractImage image) { 118 for (int i = 0; i < bounds.size(); i++) { 119 if (bounds.get(i).contains(image.getLatLon())) 120 return true; 121 } 122 return false; 123 } 81 int first = -1; 82 int last = -1; 83 int pos = 0; 84 85 // Here it gets only those images which are in the downloaded 86 // area. 87 for (MapillaryAbstractImage img : images) { 88 if (first == -1 && isInside(img)) 89 first = pos; 90 else if (first != -1 && last == -1 && !isInside(img)) 91 last = pos; 92 else if (last != -1 && isInside(img)) 93 last = -1; 94 pos++; 95 } 96 if (last == -1) { 97 last = pos; 98 } 99 if (first == -1) 100 continue; 101 List<MapillaryImage> finalImages = images.subList(first, last); 102 for (MapillaryImage img : finalImages) { 103 MapillaryData.getInstance().getImages().remove(img); 104 img.setSequence(sequence); 105 } 106 MapillaryData.getInstance().addWithoutUpdate( 107 new ArrayList<MapillaryAbstractImage>(finalImages)); 108 sequence.add(finalImages); 109 } 110 } catch (IOException e) { 111 Main.error("Error reading the url " + url 112 + " might be a Mapillary problem."); 113 } 114 } 115 116 private boolean isInside(MapillaryAbstractImage image) { 117 for (int i = 0; i < bounds.size(); i++) { 118 if (bounds.get(i).contains(image.getLatLon())) 119 return true; 120 } 121 return false; 122 } 124 123 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySignDownloaderThread.java
r31277 r31278 19 19 public class MapillarySignDownloaderThread implements Runnable { 20 20 21 22 21 private final String url; 22 private final ExecutorService ex; 23 23 24 25 26 27 24 public MapillarySignDownloaderThread(ExecutorService ex, String url) { 25 this.ex = ex; 26 this.url = url; 27 } 28 28 29 @Override 30 public void run() { 31 BufferedReader br; 32 try { 33 br = new BufferedReader(new InputStreamReader( 34 new URL(url).openStream())); 35 JsonObject jsonobj = Json.createReader(br).readObject(); 36 if (!jsonobj.getBoolean("more")) { 37 ex.shutdown(); 38 } 39 JsonArray jsonarr = jsonobj.getJsonArray("ims"); 40 for (int i = 0; i < jsonarr.size(); i++) { 41 JsonArray rects = jsonarr.getJsonObject(i) 42 .getJsonArray("rects"); 43 JsonArray rectversions = jsonarr.getJsonObject(i).getJsonArray( 44 "rectversions"); 45 String key = jsonarr.getJsonObject(i).getString("key"); 46 if (rectversions != null) { 47 for (int j = 0; j < rectversions.size(); j++) { 48 rects = rectversions.getJsonObject(j).getJsonArray("rects"); 49 for (int k = 0; k < rects.size(); k++) { 50 JsonObject data = rects.getJsonObject(k); 51 for (MapillaryAbstractImage image : MapillaryData 52 .getInstance().getImages()) 53 if (image instanceof MapillaryImage 54 && ((MapillaryImage) image).getKey() 55 .equals(key)) 56 ((MapillaryImage) image).addSign(data 57 .getString("type")); 58 } 59 } 60 } 29 @Override 30 public void run() { 31 BufferedReader br; 32 try { 33 br = new BufferedReader(new InputStreamReader( 34 new URL(url).openStream())); 35 JsonObject jsonobj = Json.createReader(br).readObject(); 36 if (!jsonobj.getBoolean("more")) { 37 ex.shutdown(); 38 } 39 JsonArray jsonarr = jsonobj.getJsonArray("ims"); 40 for (int i = 0; i < jsonarr.size(); i++) { 41 JsonArray rects = jsonarr.getJsonObject(i) 42 .getJsonArray("rects"); 43 JsonArray rectversions = jsonarr.getJsonObject(i).getJsonArray( 44 "rectversions"); 45 String key = jsonarr.getJsonObject(i).getString("key"); 46 if (rectversions != null) { 47 for (int j = 0; j < rectversions.size(); j++) { 48 rects = rectversions.getJsonObject(j).getJsonArray( 49 "rects"); 50 for (int k = 0; k < rects.size(); k++) { 51 JsonObject data = rects.getJsonObject(k); 52 for (MapillaryAbstractImage image : MapillaryData 53 .getInstance().getImages()) 54 if (image instanceof MapillaryImage 55 && ((MapillaryImage) image).getKey() 56 .equals(key)) 57 ((MapillaryImage) image).addSign(data 58 .getString("type")); 59 } 60 } 61 } 61 62 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 63 // Just one sign on the picture 64 else if (rects != null) { 65 for (int j = 0; j < rects.size(); j++) { 66 JsonObject data = rects.getJsonObject(j); 67 for (MapillaryAbstractImage image : MapillaryData 68 .getInstance().getImages()) 69 if (image instanceof MapillaryImage 70 && ((MapillaryImage) image).getKey() 71 .equals(key)) 72 ((MapillaryImage) image).addSign(data 73 .getString("type")); 74 } 75 } 76 } 77 } catch (MalformedURLException e) { 78 Main.error(e); 79 } catch (IOException e) { 80 Main.error(e); 81 } 82 } 82 83 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/downloads/MapillarySquareDownloadManagerThread.java
r31277 r31278 21 21 public class MapillarySquareDownloadManagerThread implements Runnable { 22 22 23 24 25 23 private final String urlImages; 24 private final String urlSequences; 25 private final String urlSigns; 26 26 27 28 29 30 31 32 27 public MapillarySquareDownloadManagerThread(String urlImages, 28 String urlSequences, String urlSigns) { 29 this.urlImages = urlImages; 30 this.urlSequences = urlSequences; 31 this.urlSigns = urlSigns; 32 } 33 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 34 public void run() { 35 Main.map.statusLine.setHelpText("Downloading images from Mapillary"); 36 try { 37 downloadSequences(); 38 Main.map.statusLine.setHelpText("Downloading image's information"); 39 completeImages(); 40 Main.map.statusLine.setHelpText("Downloading signs"); 41 downloadSigns(); 42 } catch (InterruptedException e) { 43 Main.error(e); 44 } 45 if (MapillaryData.getInstance().getImages().size() > 0) 46 Main.map.statusLine.setHelpText(tr("Total images: ") 47 + MapillaryData.getInstance().getImages().size()); 48 else 49 Main.map.statusLine.setHelpText(tr("No images found")); 50 MapillaryData.getInstance().dataUpdated(); 51 } 52 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 53 private void downloadSequences() throws InterruptedException { 54 ThreadPoolExecutor ex = new ThreadPoolExecutor(3, 5, 25, 55 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5)); 56 int page = 0; 57 while (!ex.isShutdown()) { 58 ex.execute(new MapillarySequenceDownloadThread(ex, urlSequences 59 + "&page=" + page + "&limit=1")); 60 while (ex.getQueue().remainingCapacity() == 0) 61 Thread.sleep(100); 62 page++; 63 } 64 ex.awaitTermination(15, TimeUnit.SECONDS); 65 MapillaryData.getInstance().dataUpdated(); 66 } 67 67 68 69 70 71 72 73 74 75 76 77 78 79 80 68 private void completeImages() throws InterruptedException { 69 ThreadPoolExecutor ex = new ThreadPoolExecutor(3, 5, 25, 70 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5)); 71 int page = 0; 72 while (!ex.isShutdown()) { 73 ex.execute(new MapillaryImageInfoDownloaderThread(ex, urlImages 74 + "&page=" + page + "&limit=20")); 75 while (ex.getQueue().remainingCapacity() == 0) 76 Thread.sleep(100); 77 page++; 78 } 79 ex.awaitTermination(15, TimeUnit.SECONDS); 80 } 81 81 82 83 84 85 86 87 88 89 90 91 92 93 94 82 private void downloadSigns() throws InterruptedException { 83 ThreadPoolExecutor ex = new ThreadPoolExecutor(3, 5, 25, 84 TimeUnit.SECONDS, new ArrayBlockingQueue<Runnable>(5)); 85 int page = 0; 86 while (!ex.isShutdown()) { 87 ex.execute(new MapillarySignDownloaderThread(ex, urlSigns 88 + "&page=" + page + "&limit=20")); 89 while (ex.getQueue().remainingCapacity() == 0) 90 Thread.sleep(100); 91 page++; 92 } 93 ex.awaitTermination(15, TimeUnit.SECONDS); 94 } 95 95 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/HyperlinkLabel.java
r31256 r31278 21 21 public class HyperlinkLabel extends JLabel implements ActionListener { 22 22 23 24 23 private String text; 24 private URL url; 25 25 26 27 28 29 30 31 32 26 /** 27 * Creates a new HyperlinlLabel. 28 */ 29 public HyperlinkLabel() { 30 super(tr("View in website"), SwingUtilities.RIGHT); 31 this.addActionListener(this); 32 setCursor(Cursor.getPredefinedCursor(Cursor.HAND_CURSOR)); 33 33 34 35 34 enableEvents(MouseEvent.MOUSE_EVENT_MASK); 35 } 36 36 37 38 39 40 41 42 43 37 /** 38 * Sets the text of the label. 39 */ 40 public void setText(String text) { 41 super.setText("<html><font color=\"#0000CF\" size=\"2\">" + text + "</font></html>"); //$NON-NLS-1$ //$NON-NLS-2$ 42 this.text = text; 43 } 44 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 45 /** 46 * Sets a new URL, just pass the key of the image or null if there is none. 47 * 48 * @param key 49 */ 50 public void setURL(String key) { 51 if (key == null) { 52 this.url = null; 53 return; 54 } 55 try { 56 this.url = new URL("http://www.mapillary.com/map/im/" + key); 57 } catch (MalformedURLException e) { 58 Main.error(e); 59 } 60 } 61 61 62 63 64 65 66 67 62 /** 63 * Returns the text set by the user. 64 */ 65 public String getNormalText() { 66 return text; 67 } 68 68 69 70 71 72 73 74 75 76 77 69 /** 70 * Processes mouse events and responds to clicks. 71 */ 72 protected void processMouseEvent(MouseEvent evt) { 73 super.processMouseEvent(evt); 74 if (evt.getID() == MouseEvent.MOUSE_CLICKED) 75 fireActionPerformed(new ActionEvent(this, 76 ActionEvent.ACTION_PERFORMED, getNormalText())); 77 } 78 78 79 80 81 82 83 84 85 79 /** 80 * Adds an ActionListener to the list of listeners receiving notifications 81 * when the label is clicked. 82 */ 83 public void addActionListener(ActionListener listener) { 84 listenerList.add(ActionListener.class, listener); 85 } 86 86 87 88 89 90 91 92 93 87 /** 88 * Removes the given ActionListener from the list of listeners receiving 89 * notifications when the label is clicked. 90 */ 91 public void removeActionListener(ActionListener listener) { 92 listenerList.remove(ActionListener.class, listener); 93 } 94 94 95 96 97 98 99 100 101 102 103 104 105 106 95 /** 96 * Fires an ActionEvent to all interested listeners. 97 */ 98 protected void fireActionPerformed(ActionEvent evt) { 99 Object[] listeners = listenerList.getListenerList(); 100 for (int i = 0; i < listeners.length; i += 2) { 101 if (listeners[i] == ActionListener.class) { 102 ActionListener listener = (ActionListener) listeners[i + 1]; 103 listener.actionPerformed(evt); 104 } 105 } 106 } 107 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 108 @Override 109 public void actionPerformed(ActionEvent e) { 110 if (this.url == null) 111 return; 112 Desktop desktop = Desktop.getDesktop(); 113 try { 114 desktop.browse(url.toURI()); 115 } catch (IOException | URISyntaxException ex) { 116 ex.printStackTrace(); 117 } catch (UnsupportedOperationException ex) { 118 Runtime runtime = Runtime.getRuntime(); 119 try { 120 runtime.exec("xdg-open " + url); 121 } catch (IOException exc) { 122 exc.printStackTrace(); 123 } 124 } 125 } 126 126 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryExportDialog.java
r31260 r31278 27 27 public class MapillaryExportDialog extends JPanel implements ActionListener { 28 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 29 protected JOptionPane optionPane; 30 /** Button to export all downloaded images. */ 31 public JRadioButton all; 32 /** 33 * Button to export all images in the sequence of the selected 34 * MapillaryImage. 35 */ 36 public JRadioButton sequence; 37 /** 38 * Button to export all images belonging to the selected MapillaryImage 39 * objects. 40 */ 41 public JRadioButton selected; 42 public JRadioButton rewrite; 43 public ButtonGroup group; 44 protected JButton choose; 45 protected JLabel path; 46 public JFileChooser chooser; 47 protected String exportDirectory; 48 48 49 50 49 public MapillaryExportDialog() { 50 setLayout(new BoxLayout(this, BoxLayout.PAGE_AXIS)); 51 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 52 group = new ButtonGroup(); 53 all = new JRadioButton(tr("Export all images")); 54 sequence = new JRadioButton(tr("Export selected sequence")); 55 selected = new JRadioButton(tr("Export selected images")); 56 rewrite = new JRadioButton(tr("Rewrite imported images")); 57 group.add(all); 58 group.add(sequence); 59 group.add(selected); 60 group.add(rewrite); 61 // Some options are disabled depending on the circumstances 62 if (MapillaryData.getInstance().getSelectedImage() == null 63 || !(MapillaryData.getInstance().getSelectedImage() instanceof MapillaryImage && ((MapillaryImage) MapillaryData 64 .getInstance().getSelectedImage()).getSequence() != null)) { 65 sequence.setEnabled(false); 66 } 67 if (MapillaryData.getInstance().getMultiSelectedImages().isEmpty()) { 68 selected.setEnabled(false); 69 } 70 path = new JLabel(tr("Select a folder")); 71 choose = new JButton(tr("Explore")); 72 choose.addActionListener(this); 73 73 74 75 76 77 78 79 80 81 82 83 74 // All options belong to the same jpanel so the are in line. 75 JPanel jpanel = new JPanel(); 76 jpanel.setLayout(new BoxLayout(jpanel, BoxLayout.PAGE_AXIS)); 77 jpanel.add(all); 78 jpanel.add(sequence); 79 jpanel.add(selected); 80 jpanel.add(rewrite); 81 jpanel.setAlignmentX(Component.CENTER_ALIGNMENT); 82 path.setAlignmentX(Component.CENTER_ALIGNMENT); 83 choose.setAlignmentX(Component.CENTER_ALIGNMENT); 84 84 85 86 87 88 85 add(jpanel); 86 add(path); 87 add(choose); 88 } 89 89 90 91 92 93 94 95 96 97 98 99 100 90 /** 91 * Creates the folder choser GUI. 92 */ 93 @Override 94 public void actionPerformed(ActionEvent e) { 95 chooser = new JFileChooser(); 96 chooser.setCurrentDirectory(new java.io.File(System 97 .getProperty("user.home"))); 98 chooser.setDialogTitle(tr("Select a directory")); 99 chooser.setFileSelectionMode(JFileChooser.DIRECTORIES_ONLY); 100 chooser.setAcceptAllFileFilterUsed(false); 101 101 102 103 104 105 106 102 if (chooser.showOpenDialog(this) == JFileChooser.APPROVE_OPTION) { 103 path.setText(chooser.getSelectedFile().toString()); 104 this.updateUI(); 105 } 106 } 107 107 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryHistoryDialog.java
r31262 r31278 31 31 32 32 public class MapillaryHistoryDialog extends ToggleDialog implements 33 33 MapillaryRecordListener { 34 34 35 35 public static MapillaryHistoryDialog INSTANCE; 36 36 37 38 39 40 41 42 37 private final DefaultTreeModel undoTreeModel = new DefaultTreeModel( 38 new DefaultMutableTreeNode()); 39 private final DefaultTreeModel redoTreeModel = new DefaultTreeModel( 40 new DefaultMutableTreeNode()); 41 private final JTree undoTree = new JTree(undoTreeModel); 42 private final JTree redoTree = new JTree(redoTreeModel); 43 43 44 45 44 private JSeparator separator = new JSeparator(); 45 private Component spacer = Box.createRigidArea(new Dimension(0, 3)); 46 46 47 48 47 private SideButton undoButton; 48 private SideButton redoButton; 49 49 50 51 52 tr("Open Mapillary history dialog"),Shortcut.registerShortcut(53 54 55 50 public MapillaryHistoryDialog() { 51 super(tr("Mapillary history"), "mapillaryhistory.png", 52 tr("Open Mapillary history dialog"), Shortcut.registerShortcut( 53 tr("Mapillary history"), 54 tr("Open Mapillary history dialog"), KeyEvent.VK_M, 55 Shortcut.NONE), 200); 56 56 57 57 MapillaryRecord.getInstance().addListener(this); 58 58 59 60 61 62 63 64 65 66 59 undoTree.expandRow(0); 60 undoTree.setShowsRootHandles(true); 61 undoTree.setRootVisible(false); 62 undoTree.setCellRenderer(new MapillaryCellRenderer()); 63 redoTree.expandRow(0); 64 redoTree.setCellRenderer(new MapillaryCellRenderer()); 65 redoTree.setShowsRootHandles(true); 66 redoTree.setRootVisible(false); 67 67 68 69 70 71 72 73 74 75 76 77 68 JPanel treesPanel = new JPanel(new GridBagLayout()); 69 treesPanel.add(spacer, GBC.eol()); 70 spacer.setVisible(false); 71 treesPanel.add(undoTree, GBC.eol().fill(GBC.HORIZONTAL)); 72 separator.setVisible(false); 73 treesPanel.add(separator, GBC.eol().fill(GBC.HORIZONTAL)); 74 treesPanel.add(redoTree, GBC.eol().fill(GBC.HORIZONTAL)); 75 treesPanel.add(Box.createRigidArea(new Dimension(0, 0)), GBC.std() 76 .weight(0, 1)); 77 treesPanel.setBackground(redoTree.getBackground()); 78 78 79 80 79 undoButton = new SideButton(new UndoAction()); 80 redoButton = new SideButton(new RedoAction()); 81 81 82 83 84 82 createLayout(treesPanel, true, 83 Arrays.asList(new SideButton[] { undoButton, redoButton })); 84 } 85 85 86 87 88 89 90 86 public static MapillaryHistoryDialog getInstance() { 87 if (INSTANCE == null) 88 INSTANCE = new MapillaryHistoryDialog(); 89 return INSTANCE; 90 } 91 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 92 private void buildTree() { 93 redoButton.setEnabled(true); 94 undoButton.setEnabled(true); 95 ArrayList<MapillaryCommand> commands = MapillaryRecord.getInstance().commandList; 96 int position = MapillaryRecord.getInstance().position; 97 ArrayList<MapillaryCommand> undoCommands = new ArrayList<>(); 98 if (position >= 0) 99 undoCommands = new ArrayList<>(commands.subList(0, position + 1)); 100 else 101 undoButton.setEnabled(false); 102 ArrayList<MapillaryCommand> redoCommands = new ArrayList<>(); 103 if (commands.size() > 0 && position + 1 < commands.size()) 104 redoCommands = new ArrayList<>(commands.subList(position + 1, 105 commands.size())); 106 else 107 redoButton.setEnabled(false); 108 108 109 110 109 DefaultMutableTreeNode redoRoot = new DefaultMutableTreeNode(); 110 DefaultMutableTreeNode undoRoot = new DefaultMutableTreeNode(); 111 111 112 113 114 115 116 117 118 119 112 for (MapillaryCommand command : undoCommands) { 113 if (command != null) 114 undoRoot.add(new DefaultMutableTreeNode(command.toString())); 115 } 116 for (MapillaryCommand command : redoCommands) { 117 if (command != null) 118 redoRoot.add(new DefaultMutableTreeNode(command.toString())); 119 } 120 120 121 122 123 121 separator 122 .setVisible(!undoCommands.isEmpty() || !redoCommands.isEmpty()); 123 spacer.setVisible(undoCommands.isEmpty() && !redoCommands.isEmpty()); 124 124 125 126 127 125 undoTreeModel.setRoot(undoRoot); 126 redoTreeModel.setRoot(redoRoot); 127 } 128 128 129 130 131 132 129 @Override 130 public void recordChanged() { 131 buildTree(); 132 } 133 133 134 134 private class UndoAction extends AbstractAction { 135 135 136 137 138 139 136 public UndoAction() { 137 putValue(NAME, tr("Undo")); 138 putValue(SMALL_ICON, ImageProvider.get("undo")); 139 } 140 140 141 142 143 144 141 @Override 142 public void actionPerformed(ActionEvent arg0) { 143 MapillaryRecord.getInstance().undo(); 144 } 145 145 146 146 } 147 147 148 149 150 151 152 148 private class RedoAction extends AbstractAction { 149 public RedoAction() { 150 putValue(NAME, tr("Redo")); 151 putValue(SMALL_ICON, ImageProvider.get("redo")); 152 } 153 153 154 155 156 157 154 @Override 155 public void actionPerformed(ActionEvent arg0) { 156 MapillaryRecord.getInstance().redo(); 157 } 158 158 159 159 } 160 160 161 162 163 164 165 166 167 168 169 170 171 161 private static class MapillaryCellRenderer extends DefaultTreeCellRenderer { 162 @Override 163 public Component getTreeCellRendererComponent(JTree tree, Object value, 164 boolean sel, boolean expanded, boolean leaf, int row, 165 boolean hasFocus) { 166 super.getTreeCellRendererComponent(tree, value, sel, expanded, 167 leaf, row, hasFocus); 168 setIcon(ImageProvider.get("data/node.png")); 169 return this; 170 } 171 } 172 172 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryImageDisplay.java
r31277 r31278 33 33 public class MapillaryImageDisplay extends JComponent { 34 34 35 private static final int DRAG_BUTTON = Main.pref.getInteger("mapillary.picture-drag-button", 3); 36 private static final int OPTION_BUTTON = Main.pref.getInteger("mapillary.picture-option-button", 2); 37 private static final int ZOOM_BUTTON = Main.pref.getInteger("mapillary.picture-zoom-button", 1); 38 39 /** The image currently displayed */ 40 private transient BufferedImage image = null; 41 42 /** 43 * The rectangle (in image coordinates) of the image that is visible. This 44 * rectangle is calculated each time the zoom is modified 45 */ 46 private Rectangle visibleRect = null; 47 48 /** 49 * When a selection is done, the rectangle of the selection (in image 50 * coordinates) 51 */ 52 private Rectangle selectedRect = null; 53 54 public HyperlinkLabel hyperlink; 55 56 private class ImgDisplayMouseListener implements MouseListener, 57 MouseWheelListener, MouseMotionListener { 58 private boolean mouseIsDragging = false; 59 private long lastTimeForMousePoint = 0L; 60 private Point mousePointInImg = null; 61 62 /** 63 * Zoom in and out, trying to preserve the point of the image that was 64 * under the mouse cursor at the same place 65 */ 66 @Override 67 public void mouseWheelMoved(MouseWheelEvent e) { 68 Image image; 69 Rectangle visibleRect; 70 synchronized (MapillaryImageDisplay.this) { 71 image = MapillaryImageDisplay.this.image; 72 visibleRect = MapillaryImageDisplay.this.visibleRect; 73 } 74 mouseIsDragging = false; 75 selectedRect = null; 76 if (image == null) 77 return; 78 // Calculate the mouse cursor position in image coordinates, so that 79 // we can center the zoom 80 // on that mouse position. 81 // To avoid issues when the user tries to zoom in on the image 82 // borders, this point is not calculated 83 // again if there was less than 1.5seconds since the last event. 84 if (e.getWhen() - lastTimeForMousePoint > 1500 85 || mousePointInImg == null) { 86 lastTimeForMousePoint = e.getWhen(); 87 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY()); 88 } 89 // Applicate the zoom to the visible rectangle in image coordinates 90 if (e.getWheelRotation() > 0) { 91 visibleRect.width = visibleRect.width * 3 / 2; 92 visibleRect.height = visibleRect.height * 3 / 2; 93 } else { 94 visibleRect.width = visibleRect.width * 2 / 3; 95 visibleRect.height = visibleRect.height * 2 / 3; 96 } 97 // Check that the zoom doesn't exceed 2:1 98 if (visibleRect.width < getSize().width / 2) { 99 visibleRect.width = getSize().width / 2; 100 } 101 if (visibleRect.height < getSize().height / 2) { 102 visibleRect.height = getSize().height / 2; 103 } 104 // Set the same ratio for the visible rectangle and the display area 105 int hFact = visibleRect.height * getSize().width; 106 int wFact = visibleRect.width * getSize().height; 107 if (hFact > wFact) { 108 visibleRect.width = hFact / getSize().height; 109 } else { 110 visibleRect.height = wFact / getSize().width; 111 } 112 // The size of the visible rectangle is limited by the image size. 113 checkVisibleRectSize(image, visibleRect); 114 // Set the position of the visible rectangle, so that the mouse 115 // cursor doesn't move on the image. 116 Rectangle drawRect = calculateDrawImageRectangle(visibleRect); 117 visibleRect.x = mousePointInImg.x 118 + ((drawRect.x - e.getX()) * visibleRect.width) 119 / drawRect.width; 120 visibleRect.y = mousePointInImg.y 121 + ((drawRect.y - e.getY()) * visibleRect.height) 122 / drawRect.height; 123 // The position is also limited by the image size 124 checkVisibleRectPos(image, visibleRect); 125 synchronized (MapillaryImageDisplay.this) { 126 MapillaryImageDisplay.this.visibleRect = visibleRect; 127 } 128 MapillaryImageDisplay.this.repaint(); 129 } 130 131 /** Center the display on the point that has been clicked */ 132 @Override 133 public void mouseClicked(MouseEvent e) { 134 // Move the center to the clicked point. 135 Image image; 136 Rectangle visibleRect; 137 synchronized (MapillaryImageDisplay.this) { 138 image = MapillaryImageDisplay.this.image; 139 visibleRect = MapillaryImageDisplay.this.visibleRect; 140 } 141 if (image == null) 142 return; 143 if (e.getButton() == OPTION_BUTTON) { 144 if (!MapillaryImageDisplay.this.visibleRect 145 .equals(new Rectangle(0, 0, image.getWidth(null), image 146 .getHeight(null)))) 147 // Zooms to 1:1 148 MapillaryImageDisplay.this.visibleRect = new Rectangle(0, 149 0, image.getWidth(null), image.getHeight(null)); 150 else 151 // Zooms to best fit. 152 MapillaryImageDisplay.this.visibleRect = new Rectangle( 153 0, 154 (image.getHeight(null) - (image.getWidth(null) * getHeight()) 155 / getWidth()) / 2, image.getWidth(null), 156 (image.getWidth(null) * getHeight()) / getWidth()); 157 MapillaryImageDisplay.this.repaint(); 158 return; 159 } else if (e.getButton() != DRAG_BUTTON) 160 return; 161 // Calculate the translation to set the clicked point the center of 162 // the view. 163 Point click = comp2imgCoord(visibleRect, e.getX(), e.getY()); 164 Point center = getCenterImgCoord(visibleRect); 165 visibleRect.x += click.x - center.x; 166 visibleRect.y += click.y - center.y; 167 checkVisibleRectPos(image, visibleRect); 168 synchronized (MapillaryImageDisplay.this) { 169 MapillaryImageDisplay.this.visibleRect = visibleRect; 170 } 171 MapillaryImageDisplay.this.repaint(); 172 } 173 174 /** 175 * Initialize the dragging, either with button 1 (simple dragging) or 176 * button 3 (selection of a picture part) 177 */ 178 @Override 179 public void mousePressed(MouseEvent e) { 180 if (image == null) { 181 mouseIsDragging = false; 182 selectedRect = null; 183 return; 184 } 185 Image image; 186 Rectangle visibleRect; 187 synchronized (MapillaryImageDisplay.this) { 188 image = MapillaryImageDisplay.this.image; 189 visibleRect = MapillaryImageDisplay.this.visibleRect; 190 } 191 if (image == null) 192 return; 193 if (e.getButton() == DRAG_BUTTON) { 194 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY()); 195 mouseIsDragging = true; 196 selectedRect = null; 197 } else if (e.getButton() == ZOOM_BUTTON) { 198 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY()); 199 checkPointInVisibleRect(mousePointInImg, visibleRect); 200 mouseIsDragging = false; 201 selectedRect = new Rectangle(mousePointInImg.x, 202 mousePointInImg.y, 0, 0); 203 MapillaryImageDisplay.this.repaint(); 204 } else { 205 mouseIsDragging = false; 206 selectedRect = null; 207 } 208 } 209 210 @Override 211 public void mouseDragged(MouseEvent e) { 212 if (!mouseIsDragging && selectedRect == null) 213 return; 214 Image image; 215 Rectangle visibleRect; 216 synchronized (MapillaryImageDisplay.this) { 217 image = MapillaryImageDisplay.this.image; 218 visibleRect = MapillaryImageDisplay.this.visibleRect; 219 } 220 if (image == null) { 221 mouseIsDragging = false; 222 selectedRect = null; 223 return; 224 } 225 if (mouseIsDragging) { 226 Point p = comp2imgCoord(visibleRect, e.getX(), e.getY()); 227 visibleRect.x += mousePointInImg.x - p.x; 228 visibleRect.y += mousePointInImg.y - p.y; 229 checkVisibleRectPos(image, visibleRect); 230 synchronized (MapillaryImageDisplay.this) { 231 MapillaryImageDisplay.this.visibleRect = visibleRect; 232 } 233 MapillaryImageDisplay.this.repaint(); 234 } else if (selectedRect != null) { 235 Point p = comp2imgCoord(visibleRect, e.getX(), e.getY()); 236 checkPointInVisibleRect(p, visibleRect); 237 Rectangle rect = new Rectangle(p.x < mousePointInImg.x ? p.x 238 : mousePointInImg.x, p.y < mousePointInImg.y ? p.y 239 : mousePointInImg.y, 240 p.x < mousePointInImg.x ? mousePointInImg.x - p.x : p.x 241 - mousePointInImg.x, 242 p.y < mousePointInImg.y ? mousePointInImg.y - p.y : p.y 243 - mousePointInImg.y); 244 checkVisibleRectSize(image, rect); 245 checkVisibleRectPos(image, rect); 246 MapillaryImageDisplay.this.selectedRect = rect; 247 MapillaryImageDisplay.this.repaint(); 248 } 249 } 250 251 @Override 252 public void mouseReleased(MouseEvent e) { 253 if (!mouseIsDragging && selectedRect == null) 254 return; 255 Image image; 256 synchronized (MapillaryImageDisplay.this) { 257 image = MapillaryImageDisplay.this.image; 258 } 259 if (image == null) { 260 mouseIsDragging = false; 261 selectedRect = null; 262 return; 263 } 264 if (mouseIsDragging) { 265 mouseIsDragging = false; 266 } else if (selectedRect != null) { 267 int oldWidth = selectedRect.width; 268 int oldHeight = selectedRect.height; 269 // Check that the zoom doesn't exceed 2:1 270 if (selectedRect.width < getSize().width / 2) { 271 selectedRect.width = getSize().width / 2; 272 } 273 if (selectedRect.height < getSize().height / 2) { 274 selectedRect.height = getSize().height / 2; 275 } 276 // Set the same ratio for the visible rectangle and the display 277 // area 278 int hFact = selectedRect.height * getSize().width; 279 int wFact = selectedRect.width * getSize().height; 280 if (hFact > wFact) { 281 selectedRect.width = hFact / getSize().height; 282 } else { 283 selectedRect.height = wFact / getSize().width; 284 } 285 // Keep the center of the selection 286 if (selectedRect.width != oldWidth) { 287 selectedRect.x -= (selectedRect.width - oldWidth) / 2; 288 } 289 if (selectedRect.height != oldHeight) { 290 selectedRect.y -= (selectedRect.height - oldHeight) / 2; 291 } 292 checkVisibleRectSize(image, selectedRect); 293 checkVisibleRectPos(image, selectedRect); 294 synchronized (MapillaryImageDisplay.this) { 295 MapillaryImageDisplay.this.visibleRect = selectedRect; 296 } 297 selectedRect = null; 298 MapillaryImageDisplay.this.repaint(); 299 } 300 } 301 302 @Override 303 public void mouseEntered(MouseEvent e) { 304 } 305 306 @Override 307 public void mouseExited(MouseEvent e) { 308 } 309 310 @Override 311 public void mouseMoved(MouseEvent e) { 312 } 313 314 private void checkPointInVisibleRect(Point p, Rectangle visibleRect) { 315 if (p.x < visibleRect.x) { 316 p.x = visibleRect.x; 317 } 318 if (p.x > visibleRect.x + visibleRect.width) { 319 p.x = visibleRect.x + visibleRect.width; 320 } 321 if (p.y < visibleRect.y) { 322 p.y = visibleRect.y; 323 } 324 if (p.y > visibleRect.y + visibleRect.height) { 325 p.y = visibleRect.y + visibleRect.height; 326 } 327 } 328 } 329 330 public MapillaryImageDisplay() { 331 ImgDisplayMouseListener mouseListener = new ImgDisplayMouseListener(); 332 addMouseListener(mouseListener); 333 addMouseWheelListener(mouseListener); 334 addMouseMotionListener(mouseListener); 335 this.setLayout(new BorderLayout()); 336 JPanel southPanel = new JPanel(); 337 southPanel.setLayout(new BorderLayout()); 338 hyperlink = new HyperlinkLabel(); 339 southPanel.add(hyperlink, BorderLayout.EAST); 340 southPanel.setOpaque(false); 341 342 add(southPanel, BorderLayout.SOUTH); 343 } 344 345 /** 346 * Sets a new picture to be displayed. 347 * 348 * @param image 349 */ 350 public void setImage(BufferedImage image) { 351 synchronized (this) { 352 this.image = image; 353 selectedRect = null; 354 if (image != null) 355 this.visibleRect = new Rectangle(0, 0, image.getWidth(null), 356 image.getHeight(null)); 357 } 358 repaint(); 359 } 360 361 /** 362 * Returns the picture that is being displayerd 363 * 364 * @return 365 */ 366 public BufferedImage getImage() { 367 return this.image; 368 } 369 370 /** 371 * Paints the visible part of the picture. 372 */ 373 public void paintComponent(Graphics g) { 374 Image image; 375 Rectangle visibleRect; 376 synchronized (this) { 377 image = this.image; 378 visibleRect = this.visibleRect; 379 } 380 if (image == null) { 381 g.setColor(Color.black); 382 String noImageStr = tr("No image"); 383 Rectangle2D noImageSize = g.getFontMetrics(g.getFont()) 384 .getStringBounds(noImageStr, g); 385 Dimension size = getSize(); 386 g.drawString(noImageStr, 387 (int) ((size.width - noImageSize.getWidth()) / 2), 388 (int) ((size.height - noImageSize.getHeight()) / 2)); 389 } else { 390 Rectangle target = calculateDrawImageRectangle(visibleRect); 391 g.drawImage(image, target.x, target.y, target.x + target.width, 392 target.y + target.height, visibleRect.x, visibleRect.y, 393 visibleRect.x + visibleRect.width, visibleRect.y 394 + visibleRect.height, null); 395 if (selectedRect != null) { 396 Point topLeft = img2compCoord(visibleRect, selectedRect.x, 397 selectedRect.y); 398 Point bottomRight = img2compCoord(visibleRect, selectedRect.x 399 + selectedRect.width, selectedRect.y 400 + selectedRect.height); 401 g.setColor(new Color(128, 128, 128, 180)); 402 g.fillRect(target.x, target.y, target.width, topLeft.y 403 - target.y); 404 g.fillRect(target.x, target.y, topLeft.x - target.x, 405 target.height); 406 g.fillRect(bottomRight.x, target.y, target.x + target.width 407 - bottomRight.x, target.height); 408 g.fillRect(target.x, bottomRight.y, target.width, target.y 409 + target.height - bottomRight.y); 410 g.setColor(Color.black); 411 g.drawRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, 412 bottomRight.y - topLeft.y); 413 } 414 } 415 } 416 417 private final Point img2compCoord(Rectangle visibleRect, int xImg, int yImg) { 418 Rectangle drawRect = calculateDrawImageRectangle(visibleRect); 419 return new Point(drawRect.x + ((xImg - visibleRect.x) * drawRect.width) 420 / visibleRect.width, drawRect.y 421 + ((yImg - visibleRect.y) * drawRect.height) 422 / visibleRect.height); 423 } 424 425 private final Point comp2imgCoord(Rectangle visibleRect, int xComp, 426 int yComp) { 427 Rectangle drawRect = calculateDrawImageRectangle(visibleRect); 428 return new Point(visibleRect.x 429 + ((xComp - drawRect.x) * visibleRect.width) / drawRect.width, 430 visibleRect.y + ((yComp - drawRect.y) * visibleRect.height) 431 / drawRect.height); 432 } 433 434 private final Point getCenterImgCoord(Rectangle visibleRect) { 435 return new Point(visibleRect.x + visibleRect.width / 2, visibleRect.y 436 + visibleRect.height / 2); 437 } 438 439 private Rectangle calculateDrawImageRectangle(Rectangle visibleRect) { 440 return calculateDrawImageRectangle(visibleRect, new Rectangle(0, 0, 441 getSize().width, getSize().height)); 442 } 443 444 /** 445 * calculateDrawImageRectangle 446 * 447 * @param imgRect 448 * the part of the image that should be drawn (in image 449 * coordinates) 450 * @param compRect 451 * the part of the component where the image should be drawn (in 452 * component coordinates) 453 * @return the part of compRect with the same width/height ratio as the 454 * image 455 */ 456 static Rectangle calculateDrawImageRectangle(Rectangle imgRect, 457 Rectangle compRect) { 458 int x, y, w, h; 459 x = 0; 460 y = 0; 461 w = compRect.width; 462 h = compRect.height; 463 int wFact = w * imgRect.height; 464 int hFact = h * imgRect.width; 465 if (wFact != hFact) { 466 if (wFact > hFact) { 467 w = hFact / imgRect.height; 468 x = (compRect.width - w) / 2; 469 } else { 470 h = wFact / imgRect.width; 471 y = (compRect.height - h) / 2; 472 } 473 } 474 return new Rectangle(x + compRect.x, y + compRect.y, w, h); 475 } 476 477 public void zoomBestFitOrOne() { 478 Image image; 479 Rectangle visibleRect; 480 synchronized (this) { 481 image = MapillaryImageDisplay.this.image; 482 visibleRect = MapillaryImageDisplay.this.visibleRect; 483 } 484 if (image == null) 485 return; 486 if (visibleRect.width != image.getWidth(null) 487 || visibleRect.height != image.getHeight(null)) { 488 // The display is not at best fit. => Zoom to best fit 489 visibleRect = new Rectangle(0, 0, image.getWidth(null), 490 image.getHeight(null)); 491 } else { 492 // The display is at best fit => zoom to 1:1 493 Point center = getCenterImgCoord(visibleRect); 494 visibleRect = new Rectangle(center.x - getWidth() / 2, center.y 495 - getHeight() / 2, getWidth(), getHeight()); 496 checkVisibleRectPos(image, visibleRect); 497 } 498 synchronized (this) { 499 this.visibleRect = visibleRect; 500 } 501 repaint(); 502 } 503 504 private final void checkVisibleRectPos(Image image, Rectangle visibleRect) { 505 if (visibleRect.x < 0) { 506 visibleRect.x = 0; 507 } 508 if (visibleRect.y < 0) { 509 visibleRect.y = 0; 510 } 511 if (visibleRect.x + visibleRect.width > image.getWidth(null)) { 512 visibleRect.x = image.getWidth(null) - visibleRect.width; 513 } 514 if (visibleRect.y + visibleRect.height > image.getHeight(null)) { 515 visibleRect.y = image.getHeight(null) - visibleRect.height; 516 } 517 } 518 519 private void checkVisibleRectSize(Image image, Rectangle visibleRect) { 520 if (visibleRect.width > image.getWidth(null)) { 521 visibleRect.width = image.getWidth(null); 522 } 523 if (visibleRect.height > image.getHeight(null)) { 524 visibleRect.height = image.getHeight(null); 525 } 526 } 35 private static final int DRAG_BUTTON = Main.pref.getInteger( 36 "mapillary.picture-drag-button", 3); 37 private static final int OPTION_BUTTON = Main.pref.getInteger( 38 "mapillary.picture-option-button", 2); 39 private static final int ZOOM_BUTTON = Main.pref.getInteger( 40 "mapillary.picture-zoom-button", 1); 41 42 /** The image currently displayed */ 43 private transient BufferedImage image = null; 44 45 /** 46 * The rectangle (in image coordinates) of the image that is visible. This 47 * rectangle is calculated each time the zoom is modified 48 */ 49 private Rectangle visibleRect = null; 50 51 /** 52 * When a selection is done, the rectangle of the selection (in image 53 * coordinates) 54 */ 55 private Rectangle selectedRect = null; 56 57 public HyperlinkLabel hyperlink; 58 59 private class ImgDisplayMouseListener implements MouseListener, 60 MouseWheelListener, MouseMotionListener { 61 private boolean mouseIsDragging = false; 62 private long lastTimeForMousePoint = 0L; 63 private Point mousePointInImg = null; 64 65 /** 66 * Zoom in and out, trying to preserve the point of the image that was 67 * under the mouse cursor at the same place 68 */ 69 @Override 70 public void mouseWheelMoved(MouseWheelEvent e) { 71 Image image; 72 Rectangle visibleRect; 73 synchronized (MapillaryImageDisplay.this) { 74 image = MapillaryImageDisplay.this.image; 75 visibleRect = MapillaryImageDisplay.this.visibleRect; 76 } 77 mouseIsDragging = false; 78 selectedRect = null; 79 if (image == null) 80 return; 81 // Calculate the mouse cursor position in image coordinates, so that 82 // we can center the zoom 83 // on that mouse position. 84 // To avoid issues when the user tries to zoom in on the image 85 // borders, this point is not calculated 86 // again if there was less than 1.5seconds since the last event. 87 if (e.getWhen() - lastTimeForMousePoint > 1500 88 || mousePointInImg == null) { 89 lastTimeForMousePoint = e.getWhen(); 90 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY()); 91 } 92 // Applicate the zoom to the visible rectangle in image coordinates 93 if (e.getWheelRotation() > 0) { 94 visibleRect.width = visibleRect.width * 3 / 2; 95 visibleRect.height = visibleRect.height * 3 / 2; 96 } else { 97 visibleRect.width = visibleRect.width * 2 / 3; 98 visibleRect.height = visibleRect.height * 2 / 3; 99 } 100 // Check that the zoom doesn't exceed 2:1 101 if (visibleRect.width < getSize().width / 2) { 102 visibleRect.width = getSize().width / 2; 103 } 104 if (visibleRect.height < getSize().height / 2) { 105 visibleRect.height = getSize().height / 2; 106 } 107 // Set the same ratio for the visible rectangle and the display area 108 int hFact = visibleRect.height * getSize().width; 109 int wFact = visibleRect.width * getSize().height; 110 if (hFact > wFact) { 111 visibleRect.width = hFact / getSize().height; 112 } else { 113 visibleRect.height = wFact / getSize().width; 114 } 115 // The size of the visible rectangle is limited by the image size. 116 checkVisibleRectSize(image, visibleRect); 117 // Set the position of the visible rectangle, so that the mouse 118 // cursor doesn't move on the image. 119 Rectangle drawRect = calculateDrawImageRectangle(visibleRect); 120 visibleRect.x = mousePointInImg.x 121 + ((drawRect.x - e.getX()) * visibleRect.width) 122 / drawRect.width; 123 visibleRect.y = mousePointInImg.y 124 + ((drawRect.y - e.getY()) * visibleRect.height) 125 / drawRect.height; 126 // The position is also limited by the image size 127 checkVisibleRectPos(image, visibleRect); 128 synchronized (MapillaryImageDisplay.this) { 129 MapillaryImageDisplay.this.visibleRect = visibleRect; 130 } 131 MapillaryImageDisplay.this.repaint(); 132 } 133 134 /** Center the display on the point that has been clicked */ 135 @Override 136 public void mouseClicked(MouseEvent e) { 137 // Move the center to the clicked point. 138 Image image; 139 Rectangle visibleRect; 140 synchronized (MapillaryImageDisplay.this) { 141 image = MapillaryImageDisplay.this.image; 142 visibleRect = MapillaryImageDisplay.this.visibleRect; 143 } 144 if (image == null) 145 return; 146 if (e.getButton() == OPTION_BUTTON) { 147 if (!MapillaryImageDisplay.this.visibleRect 148 .equals(new Rectangle(0, 0, image.getWidth(null), image 149 .getHeight(null)))) 150 // Zooms to 1:1 151 MapillaryImageDisplay.this.visibleRect = new Rectangle(0, 152 0, image.getWidth(null), image.getHeight(null)); 153 else 154 // Zooms to best fit. 155 MapillaryImageDisplay.this.visibleRect = new Rectangle( 156 0, 157 (image.getHeight(null) - (image.getWidth(null) * getHeight()) 158 / getWidth()) / 2, image.getWidth(null), 159 (image.getWidth(null) * getHeight()) / getWidth()); 160 MapillaryImageDisplay.this.repaint(); 161 return; 162 } else if (e.getButton() != DRAG_BUTTON) 163 return; 164 // Calculate the translation to set the clicked point the center of 165 // the view. 166 Point click = comp2imgCoord(visibleRect, e.getX(), e.getY()); 167 Point center = getCenterImgCoord(visibleRect); 168 visibleRect.x += click.x - center.x; 169 visibleRect.y += click.y - center.y; 170 checkVisibleRectPos(image, visibleRect); 171 synchronized (MapillaryImageDisplay.this) { 172 MapillaryImageDisplay.this.visibleRect = visibleRect; 173 } 174 MapillaryImageDisplay.this.repaint(); 175 } 176 177 /** 178 * Initialize the dragging, either with button 1 (simple dragging) or 179 * button 3 (selection of a picture part) 180 */ 181 @Override 182 public void mousePressed(MouseEvent e) { 183 if (image == null) { 184 mouseIsDragging = false; 185 selectedRect = null; 186 return; 187 } 188 Image image; 189 Rectangle visibleRect; 190 synchronized (MapillaryImageDisplay.this) { 191 image = MapillaryImageDisplay.this.image; 192 visibleRect = MapillaryImageDisplay.this.visibleRect; 193 } 194 if (image == null) 195 return; 196 if (e.getButton() == DRAG_BUTTON) { 197 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY()); 198 mouseIsDragging = true; 199 selectedRect = null; 200 } else if (e.getButton() == ZOOM_BUTTON) { 201 mousePointInImg = comp2imgCoord(visibleRect, e.getX(), e.getY()); 202 checkPointInVisibleRect(mousePointInImg, visibleRect); 203 mouseIsDragging = false; 204 selectedRect = new Rectangle(mousePointInImg.x, 205 mousePointInImg.y, 0, 0); 206 MapillaryImageDisplay.this.repaint(); 207 } else { 208 mouseIsDragging = false; 209 selectedRect = null; 210 } 211 } 212 213 @Override 214 public void mouseDragged(MouseEvent e) { 215 if (!mouseIsDragging && selectedRect == null) 216 return; 217 Image image; 218 Rectangle visibleRect; 219 synchronized (MapillaryImageDisplay.this) { 220 image = MapillaryImageDisplay.this.image; 221 visibleRect = MapillaryImageDisplay.this.visibleRect; 222 } 223 if (image == null) { 224 mouseIsDragging = false; 225 selectedRect = null; 226 return; 227 } 228 if (mouseIsDragging) { 229 Point p = comp2imgCoord(visibleRect, e.getX(), e.getY()); 230 visibleRect.x += mousePointInImg.x - p.x; 231 visibleRect.y += mousePointInImg.y - p.y; 232 checkVisibleRectPos(image, visibleRect); 233 synchronized (MapillaryImageDisplay.this) { 234 MapillaryImageDisplay.this.visibleRect = visibleRect; 235 } 236 MapillaryImageDisplay.this.repaint(); 237 } else if (selectedRect != null) { 238 Point p = comp2imgCoord(visibleRect, e.getX(), e.getY()); 239 checkPointInVisibleRect(p, visibleRect); 240 Rectangle rect = new Rectangle(p.x < mousePointInImg.x ? p.x 241 : mousePointInImg.x, p.y < mousePointInImg.y ? p.y 242 : mousePointInImg.y, 243 p.x < mousePointInImg.x ? mousePointInImg.x - p.x : p.x 244 - mousePointInImg.x, 245 p.y < mousePointInImg.y ? mousePointInImg.y - p.y : p.y 246 - mousePointInImg.y); 247 checkVisibleRectSize(image, rect); 248 checkVisibleRectPos(image, rect); 249 MapillaryImageDisplay.this.selectedRect = rect; 250 MapillaryImageDisplay.this.repaint(); 251 } 252 } 253 254 @Override 255 public void mouseReleased(MouseEvent e) { 256 if (!mouseIsDragging && selectedRect == null) 257 return; 258 Image image; 259 synchronized (MapillaryImageDisplay.this) { 260 image = MapillaryImageDisplay.this.image; 261 } 262 if (image == null) { 263 mouseIsDragging = false; 264 selectedRect = null; 265 return; 266 } 267 if (mouseIsDragging) { 268 mouseIsDragging = false; 269 } else if (selectedRect != null) { 270 int oldWidth = selectedRect.width; 271 int oldHeight = selectedRect.height; 272 // Check that the zoom doesn't exceed 2:1 273 if (selectedRect.width < getSize().width / 2) { 274 selectedRect.width = getSize().width / 2; 275 } 276 if (selectedRect.height < getSize().height / 2) { 277 selectedRect.height = getSize().height / 2; 278 } 279 // Set the same ratio for the visible rectangle and the display 280 // area 281 int hFact = selectedRect.height * getSize().width; 282 int wFact = selectedRect.width * getSize().height; 283 if (hFact > wFact) { 284 selectedRect.width = hFact / getSize().height; 285 } else { 286 selectedRect.height = wFact / getSize().width; 287 } 288 // Keep the center of the selection 289 if (selectedRect.width != oldWidth) { 290 selectedRect.x -= (selectedRect.width - oldWidth) / 2; 291 } 292 if (selectedRect.height != oldHeight) { 293 selectedRect.y -= (selectedRect.height - oldHeight) / 2; 294 } 295 checkVisibleRectSize(image, selectedRect); 296 checkVisibleRectPos(image, selectedRect); 297 synchronized (MapillaryImageDisplay.this) { 298 MapillaryImageDisplay.this.visibleRect = selectedRect; 299 } 300 selectedRect = null; 301 MapillaryImageDisplay.this.repaint(); 302 } 303 } 304 305 @Override 306 public void mouseEntered(MouseEvent e) { 307 } 308 309 @Override 310 public void mouseExited(MouseEvent e) { 311 } 312 313 @Override 314 public void mouseMoved(MouseEvent e) { 315 } 316 317 private void checkPointInVisibleRect(Point p, Rectangle visibleRect) { 318 if (p.x < visibleRect.x) { 319 p.x = visibleRect.x; 320 } 321 if (p.x > visibleRect.x + visibleRect.width) { 322 p.x = visibleRect.x + visibleRect.width; 323 } 324 if (p.y < visibleRect.y) { 325 p.y = visibleRect.y; 326 } 327 if (p.y > visibleRect.y + visibleRect.height) { 328 p.y = visibleRect.y + visibleRect.height; 329 } 330 } 331 } 332 333 public MapillaryImageDisplay() { 334 ImgDisplayMouseListener mouseListener = new ImgDisplayMouseListener(); 335 addMouseListener(mouseListener); 336 addMouseWheelListener(mouseListener); 337 addMouseMotionListener(mouseListener); 338 this.setLayout(new BorderLayout()); 339 JPanel southPanel = new JPanel(); 340 southPanel.setLayout(new BorderLayout()); 341 hyperlink = new HyperlinkLabel(); 342 southPanel.add(hyperlink, BorderLayout.EAST); 343 southPanel.setOpaque(false); 344 345 add(southPanel, BorderLayout.SOUTH); 346 } 347 348 /** 349 * Sets a new picture to be displayed. 350 * 351 * @param image 352 */ 353 public void setImage(BufferedImage image) { 354 synchronized (this) { 355 this.image = image; 356 selectedRect = null; 357 if (image != null) 358 this.visibleRect = new Rectangle(0, 0, image.getWidth(null), 359 image.getHeight(null)); 360 } 361 repaint(); 362 } 363 364 /** 365 * Returns the picture that is being displayerd 366 * 367 * @return 368 */ 369 public BufferedImage getImage() { 370 return this.image; 371 } 372 373 /** 374 * Paints the visible part of the picture. 375 */ 376 public void paintComponent(Graphics g) { 377 Image image; 378 Rectangle visibleRect; 379 synchronized (this) { 380 image = this.image; 381 visibleRect = this.visibleRect; 382 } 383 if (image == null) { 384 g.setColor(Color.black); 385 String noImageStr = tr("No image"); 386 Rectangle2D noImageSize = g.getFontMetrics(g.getFont()) 387 .getStringBounds(noImageStr, g); 388 Dimension size = getSize(); 389 g.drawString(noImageStr, 390 (int) ((size.width - noImageSize.getWidth()) / 2), 391 (int) ((size.height - noImageSize.getHeight()) / 2)); 392 } else { 393 Rectangle target = calculateDrawImageRectangle(visibleRect); 394 g.drawImage(image, target.x, target.y, target.x + target.width, 395 target.y + target.height, visibleRect.x, visibleRect.y, 396 visibleRect.x + visibleRect.width, visibleRect.y 397 + visibleRect.height, null); 398 if (selectedRect != null) { 399 Point topLeft = img2compCoord(visibleRect, selectedRect.x, 400 selectedRect.y); 401 Point bottomRight = img2compCoord(visibleRect, selectedRect.x 402 + selectedRect.width, selectedRect.y 403 + selectedRect.height); 404 g.setColor(new Color(128, 128, 128, 180)); 405 g.fillRect(target.x, target.y, target.width, topLeft.y 406 - target.y); 407 g.fillRect(target.x, target.y, topLeft.x - target.x, 408 target.height); 409 g.fillRect(bottomRight.x, target.y, target.x + target.width 410 - bottomRight.x, target.height); 411 g.fillRect(target.x, bottomRight.y, target.width, target.y 412 + target.height - bottomRight.y); 413 g.setColor(Color.black); 414 g.drawRect(topLeft.x, topLeft.y, bottomRight.x - topLeft.x, 415 bottomRight.y - topLeft.y); 416 } 417 } 418 } 419 420 private final Point img2compCoord(Rectangle visibleRect, int xImg, int yImg) { 421 Rectangle drawRect = calculateDrawImageRectangle(visibleRect); 422 return new Point(drawRect.x + ((xImg - visibleRect.x) * drawRect.width) 423 / visibleRect.width, drawRect.y 424 + ((yImg - visibleRect.y) * drawRect.height) 425 / visibleRect.height); 426 } 427 428 private final Point comp2imgCoord(Rectangle visibleRect, int xComp, 429 int yComp) { 430 Rectangle drawRect = calculateDrawImageRectangle(visibleRect); 431 return new Point(visibleRect.x 432 + ((xComp - drawRect.x) * visibleRect.width) / drawRect.width, 433 visibleRect.y + ((yComp - drawRect.y) * visibleRect.height) 434 / drawRect.height); 435 } 436 437 private final Point getCenterImgCoord(Rectangle visibleRect) { 438 return new Point(visibleRect.x + visibleRect.width / 2, visibleRect.y 439 + visibleRect.height / 2); 440 } 441 442 private Rectangle calculateDrawImageRectangle(Rectangle visibleRect) { 443 return calculateDrawImageRectangle(visibleRect, new Rectangle(0, 0, 444 getSize().width, getSize().height)); 445 } 446 447 /** 448 * calculateDrawImageRectangle 449 * 450 * @param imgRect 451 * the part of the image that should be drawn (in image 452 * coordinates) 453 * @param compRect 454 * the part of the component where the image should be drawn (in 455 * component coordinates) 456 * @return the part of compRect with the same width/height ratio as the 457 * image 458 */ 459 static Rectangle calculateDrawImageRectangle(Rectangle imgRect, 460 Rectangle compRect) { 461 int x, y, w, h; 462 x = 0; 463 y = 0; 464 w = compRect.width; 465 h = compRect.height; 466 int wFact = w * imgRect.height; 467 int hFact = h * imgRect.width; 468 if (wFact != hFact) { 469 if (wFact > hFact) { 470 w = hFact / imgRect.height; 471 x = (compRect.width - w) / 2; 472 } else { 473 h = wFact / imgRect.width; 474 y = (compRect.height - h) / 2; 475 } 476 } 477 return new Rectangle(x + compRect.x, y + compRect.y, w, h); 478 } 479 480 public void zoomBestFitOrOne() { 481 Image image; 482 Rectangle visibleRect; 483 synchronized (this) { 484 image = MapillaryImageDisplay.this.image; 485 visibleRect = MapillaryImageDisplay.this.visibleRect; 486 } 487 if (image == null) 488 return; 489 if (visibleRect.width != image.getWidth(null) 490 || visibleRect.height != image.getHeight(null)) { 491 // The display is not at best fit. => Zoom to best fit 492 visibleRect = new Rectangle(0, 0, image.getWidth(null), 493 image.getHeight(null)); 494 } else { 495 // The display is at best fit => zoom to 1:1 496 Point center = getCenterImgCoord(visibleRect); 497 visibleRect = new Rectangle(center.x - getWidth() / 2, center.y 498 - getHeight() / 2, getWidth(), getHeight()); 499 checkVisibleRectPos(image, visibleRect); 500 } 501 synchronized (this) { 502 this.visibleRect = visibleRect; 503 } 504 repaint(); 505 } 506 507 private final void checkVisibleRectPos(Image image, Rectangle visibleRect) { 508 if (visibleRect.x < 0) { 509 visibleRect.x = 0; 510 } 511 if (visibleRect.y < 0) { 512 visibleRect.y = 0; 513 } 514 if (visibleRect.x + visibleRect.width > image.getWidth(null)) { 515 visibleRect.x = image.getWidth(null) - visibleRect.width; 516 } 517 if (visibleRect.y + visibleRect.height > image.getHeight(null)) { 518 visibleRect.y = image.getHeight(null) - visibleRect.height; 519 } 520 } 521 522 private void checkVisibleRectSize(Image image, Rectangle visibleRect) { 523 if (visibleRect.width > image.getWidth(null)) { 524 visibleRect.width = image.getWidth(null); 525 } 526 if (visibleRect.height > image.getHeight(null)) { 527 visibleRect.height = image.getHeight(null); 528 } 529 } 527 530 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryPreferenceSetting.java
r31277 r31278 14 14 public class MapillaryPreferenceSetting implements SubPreferenceSetting { 15 15 16 private JCheckBox reverseButtons = new JCheckBox(tr("Reverse buttons position when displaying images.")); 17 private JCheckBox downloadMode = new JCheckBox(tr("Download images manually")); 16 private JCheckBox reverseButtons = new JCheckBox( 17 tr("Reverse buttons position when displaying images.")); 18 private JCheckBox downloadMode = new JCheckBox( 19 tr("Download images manually")); 18 20 19 20 @Override 21 public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) { 22 return gui.getDisplayPreference(); 23 } 21 @Override 22 public TabPreferenceSetting getTabPreferenceSetting(PreferenceTabbedPane gui) { 23 return gui.getDisplayPreference(); 24 } 24 25 25 @Override 26 public void addGui(PreferenceTabbedPane gui) { 27 JPanel panel = new JPanel(); 28 29 reverseButtons.setSelected(Main.pref.getBoolean("mapillary.reverse-buttons")); 30 downloadMode.setSelected(Main.pref.getBoolean("mapillary.download-manually")); 31 32 panel.setLayout(new FlowLayout(FlowLayout.LEFT)); 33 panel.add(reverseButtons); 34 panel.add(downloadMode); 26 @Override 27 public void addGui(PreferenceTabbedPane gui) { 28 JPanel panel = new JPanel(); 29 30 reverseButtons.setSelected(Main.pref 31 .getBoolean("mapillary.reverse-buttons")); 32 downloadMode.setSelected(Main.pref 33 .getBoolean("mapillary.download-manually")); 34 35 panel.setLayout(new FlowLayout(FlowLayout.LEFT)); 36 panel.add(reverseButtons); 37 panel.add(downloadMode); 35 38 gui.getDisplayPreference().addSubTab(this, "Mapillary", panel); 36 39 } 37 40 38 39 41 @Override 42 public boolean ok() { 40 43 boolean mod = false; 41 44 Main.pref.put("mapillary.reverse-buttons", reverseButtons.isSelected()); 42 45 Main.pref.put("mapillary.download-manually", downloadMode.isSelected()); 43 46 return mod; 44 47 } 45 48 46 47 48 49 49 @Override 50 public boolean isExpert() { 51 return false; 52 } 50 53 51 54 } -
applications/editors/josm/plugins/mapillary/src/org/openstreetmap/josm/plugins/mapillary/gui/MapillaryToggleDialog.java
r31275 r31278 43 43 */ 44 44 public class MapillaryToggleDialog extends ToggleDialog implements 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 349 350 351 352 353 354 355 356 357 358 359 360 361 362 363 364 365 366 367 368 369 370 371 372 373 374 375 376 377 378 379 380 381 382 383 384 385 386 387 388 389 390 391 392 393 394 395 396 397 398 399 400 401 402 403 404 405 406 407 408 409 410 411 412 413 414 415 416 417 418 419 420 421 422 423 424 425 426 427 428 429 430 431 432 433 434 435 436 437 438 439 440 441 442 443 444 445 446 447 448 449 450 451 452 453 454 455 456 457 458 459 460 461 462 463 464 465 466 467 468 469 470 471 472 473 474 475 476 477 478 479 480 481 482 45 ICachedLoaderListener, MapillaryDataListener { 46 47 public final static int NORMAL_MODE = 0; 48 public final static int SIGN_MODE = 1; 49 50 public final static String BASE_TITLE = "Mapillary picture"; 51 52 public static MapillaryToggleDialog INSTANCE; 53 54 public volatile MapillaryAbstractImage image; 55 56 public final SideButton nextButton = new SideButton(new nextPictureAction()); 57 public final SideButton previousButton = new SideButton( 58 new previousPictureAction()); 59 public final SideButton redButton = new SideButton(new redAction()); 60 public final SideButton blueButton = new SideButton(new blueAction()); 61 private List<SideButton> normalMode; 62 63 public final SideButton nextSignButton = new SideButton( 64 new NextSignAction()); 65 public final SideButton previousSignButton = new SideButton( 66 new PreviousSignAction()); 67 private List<SideButton> signMode; 68 69 private int mode; 70 71 private JPanel buttonsPanel; 72 73 public MapillaryImageDisplay mapillaryImageDisplay; 74 75 private MapillaryCache imageCache; 76 private MapillaryCache thumbnailCache; 77 78 public MapillaryToggleDialog() { 79 super(tr(BASE_TITLE), "mapillary.png", tr("Open Mapillary window"), 80 Shortcut.registerShortcut(tr("Mapillary dialog"), 81 tr("Open Mapillary main dialog"), KeyEvent.VK_M, 82 Shortcut.NONE), 200); 83 MapillaryData.getInstance().addListener(this); 84 85 mapillaryImageDisplay = new MapillaryImageDisplay(); 86 87 blueButton.setForeground(Color.BLUE); 88 redButton.setForeground(Color.RED); 89 90 normalMode = Arrays.asList(new SideButton[] { blueButton, 91 previousButton, nextButton, redButton }); 92 signMode = Arrays.asList(new SideButton[] { previousSignButton, 93 nextSignButton }); 94 95 mode = NORMAL_MODE; 96 97 createLayout(mapillaryImageDisplay, normalMode, 98 Main.pref.getBoolean("mapillary.reverse-buttons")); 99 disableAllButtons(); 100 } 101 102 public static MapillaryToggleDialog getInstance() { 103 if (INSTANCE == null) 104 INSTANCE = new MapillaryToggleDialog(); 105 return INSTANCE; 106 } 107 108 public static void destroyInstance() { 109 INSTANCE = null; 110 } 111 112 /** 113 * Switches from one mode to the other one. 114 */ 115 public void switchMode() { 116 this.removeAll(); 117 List<SideButton> list = null; 118 if (mode == NORMAL_MODE) { 119 list = signMode; 120 mode = SIGN_MODE; 121 } else if (mode == SIGN_MODE) { 122 list = normalMode; 123 mode = NORMAL_MODE; 124 } 125 126 createLayout(mapillaryImageDisplay, list, 127 Main.pref.getBoolean("mapillary.reverse-buttons")); 128 disableAllButtons(); 129 updateImage(); 130 } 131 132 /** 133 * Downloads the image of the selected MapillaryImage and sets in the 134 * MapillaryImageDisplay object. 135 */ 136 public synchronized void updateImage() { 137 if (!SwingUtilities.isEventDispatchThread()) { 138 SwingUtilities.invokeLater(new Runnable() { 139 @Override 140 public void run() { 141 updateImage(); 142 } 143 }); 144 } else { 145 if (MapillaryLayer.INSTANCE == null) { 146 return; 147 } 148 if (this.image == null) { 149 mapillaryImageDisplay.setImage(null); 150 titleBar.setTitle(tr(BASE_TITLE)); 151 disableAllButtons(); 152 return; 153 } 154 if (image instanceof MapillaryImage) { 155 mapillaryImageDisplay.hyperlink.setVisible(true); 156 MapillaryImage mapillaryImage = (MapillaryImage) this.image; 157 String title = tr(BASE_TITLE); 158 if (mapillaryImage.getUser() != null) 159 title += " -- " + mapillaryImage.getUser(); 160 if (mapillaryImage.getCapturedAt() != 0) 161 title += " -- " + mapillaryImage.getDate(); 162 titleBar.setTitle(title); 163 if (mode == NORMAL_MODE) { 164 this.nextButton.setEnabled(true); 165 this.previousButton.setEnabled(true); 166 if (mapillaryImage.next() == null) 167 this.nextButton.setEnabled(false); 168 if (mapillaryImage.previous() == null) 169 this.previousButton.setEnabled(false); 170 } else if (mode == SIGN_MODE) { 171 previousSignButton.setEnabled(true); 172 nextSignButton.setEnabled(true); 173 int i = MapillaryData 174 .getInstance() 175 .getImages() 176 .indexOf( 177 MapillaryData.getInstance() 178 .getSelectedImage()); 179 int first = -1; 180 int last = -1; 181 int c = 0; 182 for (MapillaryAbstractImage img : MapillaryData 183 .getInstance().getImages()) { 184 if (img instanceof MapillaryImage) 185 if (!((MapillaryImage) img).getSigns().isEmpty()) { 186 if (first == -1) 187 first = c; 188 last = c; 189 } 190 c++; 191 } 192 if (first >= i) 193 previousSignButton.setEnabled(false); 194 if (last <= i) 195 nextSignButton.setEnabled(false); 196 } 197 198 mapillaryImageDisplay.hyperlink.setURL(mapillaryImage.getKey()); 199 // Downloads the thumbnail. 200 this.mapillaryImageDisplay.setImage(null); 201 if (thumbnailCache != null) 202 thumbnailCache.cancelOutstandingTasks(); 203 thumbnailCache = new MapillaryCache(mapillaryImage.getKey(), 204 MapillaryCache.Type.THUMBNAIL); 205 thumbnailCache.submit(this, false); 206 207 // Downloads the full resolution image. 208 if (imageCache != null) 209 imageCache.cancelOutstandingTasks(); 210 imageCache = new MapillaryCache(mapillaryImage.getKey(), 211 MapillaryCache.Type.FULL_IMAGE); 212 imageCache.submit(this, false); 213 } else if (image instanceof MapillaryImportedImage) { 214 mapillaryImageDisplay.hyperlink.setVisible(false); 215 this.nextButton.setEnabled(false); 216 this.previousButton.setEnabled(false); 217 MapillaryImportedImage mapillaryImage = (MapillaryImportedImage) this.image; 218 try { 219 mapillaryImageDisplay.setImage(mapillaryImage.getImage()); 220 } catch (IOException e) { 221 Main.error(e); 222 } 223 mapillaryImageDisplay.hyperlink.setURL(null); 224 } 225 } 226 } 227 228 private void disableAllButtons() { 229 nextButton.setEnabled(false); 230 previousButton.setEnabled(false); 231 blueButton.setEnabled(false); 232 redButton.setEnabled(false); 233 nextSignButton.setEnabled(false); 234 previousSignButton.setEnabled(false); 235 mapillaryImageDisplay.hyperlink.setVisible(false); 236 } 237 238 /** 239 * Sets a new MapillaryImage to be shown. 240 * 241 * @param image 242 */ 243 public synchronized void setImage(MapillaryAbstractImage image) { 244 this.image = image; 245 } 246 247 /** 248 * Returns the MapillaryImage objects which is being shown. 249 * 250 * @return 251 */ 252 public synchronized MapillaryAbstractImage getImage() { 253 return this.image; 254 } 255 256 /** 257 * Action class form the next image button. 258 * 259 * @author Jorge 260 * 261 */ 262 class nextPictureAction extends AbstractAction { 263 public nextPictureAction() { 264 putValue(NAME, tr("Next picture")); 265 putValue(SHORT_DESCRIPTION, 266 tr("Shows the next picture in the sequence")); 267 } 268 269 @Override 270 public void actionPerformed(ActionEvent e) { 271 if (MapillaryToggleDialog.getInstance().getImage() != null) { 272 MapillaryData.getInstance().selectNext(); 273 } 274 } 275 } 276 277 /** 278 * Action class for the previous image button. 279 * 280 * @author Jorge 281 * 282 */ 283 class previousPictureAction extends AbstractAction { 284 public previousPictureAction() { 285 putValue(NAME, tr("Previous picture")); 286 putValue(SHORT_DESCRIPTION, 287 tr("Shows the previous picture in the sequence")); 288 } 289 290 @Override 291 public void actionPerformed(ActionEvent e) { 292 if (MapillaryToggleDialog.getInstance().getImage() != null) { 293 MapillaryData.getInstance().selectPrevious(); 294 } 295 } 296 } 297 298 /** 299 * Action class to jump to the image following the red line. 300 * 301 * @author nokutu 302 * 303 */ 304 class redAction extends AbstractAction { 305 public redAction() { 306 putValue(NAME, tr("Jump to red")); 307 putValue( 308 SHORT_DESCRIPTION, 309 tr("Jumps to the picture at the other side of the red line")); 310 } 311 312 @Override 313 public void actionPerformed(ActionEvent e) { 314 if (MapillaryToggleDialog.getInstance().getImage() != null) { 315 MapillaryData.getInstance().setSelectedImage( 316 MapillaryLayer.RED, true); 317 } 318 } 319 } 320 321 /** 322 * Action class to jump to the image following the blue line. 323 * 324 * @author nokutu 325 * 326 */ 327 class blueAction extends AbstractAction { 328 public blueAction() { 329 putValue(NAME, tr("Jump to blue")); 330 putValue( 331 SHORT_DESCRIPTION, 332 tr("Jumps to the picture at the other side of the blue line")); 333 } 334 335 @Override 336 public void actionPerformed(ActionEvent e) { 337 if (MapillaryToggleDialog.getInstance().getImage() != null) { 338 MapillaryData.getInstance().setSelectedImage( 339 MapillaryLayer.BLUE, true); 340 } 341 } 342 } 343 344 /** 345 * When the pictures are returned from the cache, they are set in the 346 * {@link MapillaryImageDisplay} object. 347 */ 348 @Override 349 public void loadingFinished(CacheEntry data, 350 CacheEntryAttributes attributes, LoadResult result) { 351 if (!SwingUtilities.isEventDispatchThread()) { 352 SwingUtilities.invokeLater(new Runnable() { 353 @Override 354 public void run() { 355 updateImage(); 356 } 357 }); 358 } else if (data != null && result == LoadResult.SUCCESS) { 359 try { 360 BufferedImage img = ImageIO.read(new ByteArrayInputStream(data 361 .getContent())); 362 if (this.mapillaryImageDisplay.getImage() == null) 363 mapillaryImageDisplay.setImage(img); 364 else if (img.getHeight() > this.mapillaryImageDisplay 365 .getImage().getHeight()) { 366 mapillaryImageDisplay.setImage(img); 367 } 368 } catch (IOException e) { 369 Main.error(e); 370 } 371 } 372 } 373 374 /** 375 * Creates the layout of the dialog. 376 * 377 * @param data 378 * The content of the dialog 379 * @param buttons 380 * The buttons where you can click 381 * @param reverse 382 * {@code true} if the buttons should go at the top; 383 * {@code false} otherwise. 384 */ 385 public void createLayout(Component data, List<SideButton> buttons, 386 boolean reverse) { 387 this.removeAll(); 388 JPanel panel = new JPanel(); 389 panel.setLayout(new BorderLayout()); 390 panel.add(data, BorderLayout.CENTER); 391 if (reverse) { 392 buttonsPanel = new JPanel(new GridLayout(1, 1)); 393 if (!buttons.isEmpty() && buttons.get(0) != null) { 394 final JPanel buttonRowPanel = new JPanel(Main.pref.getBoolean( 395 "dialog.align.left", false) ? new FlowLayout( 396 FlowLayout.LEFT) : new GridLayout(1, buttons.size())); 397 buttonsPanel.add(buttonRowPanel); 398 for (SideButton button : buttons) 399 buttonRowPanel.add(button); 400 } 401 panel.add(buttonsPanel, BorderLayout.NORTH); 402 createLayout(panel, true, null); 403 } else 404 createLayout(panel, true, buttons); 405 this.add(titleBar, BorderLayout.NORTH); 406 } 407 408 @Override 409 public void selectedImageChanged(MapillaryAbstractImage oldImage, 410 MapillaryAbstractImage newImage) { 411 setImage(MapillaryData.getInstance().getSelectedImage()); 412 updateImage(); 413 } 414 415 /** 416 * Action class to jump to the next picture containing a sign. 417 * 418 * @author nokutu 419 * 420 */ 421 class NextSignAction extends AbstractAction { 422 public NextSignAction() { 423 putValue(NAME, tr("Next Sign")); 424 putValue(SHORT_DESCRIPTION, 425 tr("Jumps to the next picture that contains a sign")); 426 } 427 428 @Override 429 public void actionPerformed(ActionEvent e) { 430 if (MapillaryToggleDialog.getInstance().getImage() != null) { 431 int i = MapillaryData 432 .getInstance() 433 .getImages() 434 .indexOf(MapillaryData.getInstance().getSelectedImage()); 435 for (int j = i + 1; j < MapillaryData.getInstance().getImages() 436 .size(); j++) { 437 MapillaryAbstractImage img = MapillaryData.getInstance() 438 .getImages().get(j); 439 if (img instanceof MapillaryImage) 440 if (!((MapillaryImage) img).getSigns().isEmpty()) { 441 MapillaryData.getInstance().setSelectedImage(img, 442 true); 443 return; 444 } 445 } 446 } 447 } 448 } 449 450 /** 451 * Action class to jump to the previous picture containing a sign. 452 * 453 * @author nokutu 454 * 455 */ 456 class PreviousSignAction extends AbstractAction { 457 public PreviousSignAction() { 458 putValue(NAME, tr("Previous Sign")); 459 putValue(SHORT_DESCRIPTION, 460 tr("Jumps to the previous picture that contains a sign")); 461 } 462 463 @Override 464 public void actionPerformed(ActionEvent e) { 465 if (MapillaryToggleDialog.getInstance().getImage() != null) { 466 int i = MapillaryData 467 .getInstance() 468 .getImages() 469 .indexOf(MapillaryData.getInstance().getSelectedImage()); 470 for (int j = i - 1; j >= 0; j--) { 471 MapillaryAbstractImage img = MapillaryData.getInstance() 472 .getImages().get(j); 473 if (img instanceof MapillaryImage) 474 if (!((MapillaryImage) img).getSigns().isEmpty()) { 475 MapillaryData.getInstance().setSelectedImage(img, 476 true); 477 return; 478 } 479 } 480 } 481 } 482 } 483 483 }
Note:
See TracChangeset
for help on using the changeset viewer.