Changeset 34329 in osm for applications/editors/josm/plugins/MicrosoftStreetside/src
- Timestamp:
- 2018-06-20T06:54:45+02:00 (7 years ago)
- Location:
- applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside
- Files:
-
- 3 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/StreetsideData.java
r34317 r34329 59 59 */ 60 60 protected StreetsideData() { 61 selectedImage = null;62 bounds = new CopyOnWriteArrayList<>();61 this.selectedImage = null; 62 this.bounds = new CopyOnWriteArrayList<>(); 63 63 64 64 // Adds the basic set of listeners. … … 135 135 */ 136 136 public void addMultiSelectedImage(final StreetsideAbstractImage image) { 137 if (! multiSelectedImages.contains(image)) {138 if ( getSelectedImage() == null) {137 if (!this.multiSelectedImages.contains(image)) { 138 if (this.getSelectedImage() == null) { 139 139 this.setSelectedImage(image); 140 140 } else { 141 multiSelectedImages.add(image);141 this.multiSelectedImages.add(image); 142 142 } 143 143 } … … 152 152 */ 153 153 public void addMultiSelectedImage(Collection<StreetsideAbstractImage> images) { 154 images.stream().filter(image -> ! multiSelectedImages.contains(image)).forEach(image -> {155 if ( getSelectedImage() == null) {154 images.stream().filter(image -> !this.multiSelectedImages.contains(image)).forEach(image -> { 155 if (this.getSelectedImage() == null) { 156 156 this.setSelectedImage(image); 157 157 } else { 158 multiSelectedImages.add(image);158 this.multiSelectedImages.add(image); 159 159 } 160 160 }); … … 190 190 */ 191 191 public StreetsideAbstractImage getHighlightedImage() { 192 return highlightedImage;192 return this.highlightedImage; 193 193 } 194 194 … … 317 317 */ 318 318 public void setSelectedImage(StreetsideAbstractImage image, boolean zoom) { 319 StreetsideAbstractImage oldImage = selectedImage;320 selectedImage = image;321 multiSelectedImages.clear();319 StreetsideAbstractImage oldImage = this.selectedImage; 320 this.selectedImage = image; 321 this.multiSelectedImages.clear(); 322 322 final MapView mv = StreetsidePlugin.getMapView(); 323 323 if (image != null) { 324 multiSelectedImages.add(image);324 this.multiSelectedImages.add(image); 325 325 if (mv != null && image instanceof StreetsideImage) { 326 326 StreetsideImage streetsideImage = (StreetsideImage) image; 327 327 328 328 // Downloading thumbnails of surrounding pictures. 329 StreetsideData.downloadSurroundingImages(streetsideImage);329 downloadSurroundingImages(streetsideImage); 330 330 } 331 331 } … … 333 333 mv.zoomTo(selectedImage.getMovingLatLon()); 334 334 } 335 fireSelectedImageChanged(oldImage, selectedImage);335 fireSelectedImageChanged(oldImage, this.selectedImage); 336 336 StreetsideLayer.invalidateInstance(); 337 337 } … … 379 379 */ 380 380 public Set<StreetsideAbstractImage> getMultiSelectedImages() { 381 return multiSelectedImages;381 return this.multiSelectedImages; 382 382 } 383 383 -
applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/StreetsideLayer.java
r34325 r34329 12 12 import java.awt.RenderingHints; 13 13 import java.awt.TexturePaint; 14 import java.awt.event.ActionEvent; 14 15 import java.awt.geom.Line2D; 16 import java.awt.geom.Path2D; 15 17 import java.awt.image.BufferedImage; 16 18 import java.util.Comparator; … … 18 20 import java.util.Optional; 19 21 22 import javax.swing.AbstractAction; 20 23 import javax.swing.Action; 21 24 import javax.swing.Icon; 25 import javax.swing.JComponent; 26 import javax.swing.KeyStroke; 22 27 23 28 import org.openstreetmap.josm.Main; … … 34 39 import org.openstreetmap.josm.gui.layer.AbstractModifiableLayer; 35 40 import org.openstreetmap.josm.gui.layer.Layer; 36 import org.openstreetmap.josm.gui.layer.LayerManager;37 41 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeEvent; 38 42 import org.openstreetmap.josm.gui.layer.MainLayerManager.ActiveLayerChangeListener; 39 43 import org.openstreetmap.josm.plugins.streetside.cache.CacheUtils; 44 import org.openstreetmap.josm.plugins.streetside.gui.StreetsideChangesetDialog; 40 45 import org.openstreetmap.josm.plugins.streetside.gui.StreetsideMainDialog; 41 import org.openstreetmap.josm.plugins.streetside.history.StreetsideRecord;42 46 import org.openstreetmap.josm.plugins.streetside.io.download.StreetsideDownloader; 43 47 import org.openstreetmap.josm.plugins.streetside.io.download.StreetsideDownloader.DOWNLOAD_MODE; … … 51 55 import org.openstreetmap.josm.tools.I18n; 52 56 import org.openstreetmap.josm.tools.ImageProvider.ImageSizes; 57 import org.openstreetmap.josm.tools.Logging; 58 59 import org.openstreetmap.josm.plugins.streetside.history.StreetsideRecord; 53 60 54 61 /** … … 61 68 ActiveLayerChangeListener, StreetsideDataListener { 62 69 63 64 65 66 67 68 69 70 71 72 73 Math.pow(StreetsideLayer.TRAFFIC_SIGN_SIZE, 2) - Math.pow(StreetsideLayer.TRAFFIC_SIGN_SIZE / 2d, 2)74 70 /** The radius of the image marker */ 71 private static final int IMG_MARKER_RADIUS = 7; 72 /** The radius of the circular sector that indicates the camera angle */ 73 private static final int CA_INDICATOR_RADIUS = 15; 74 /** The angle of the circular sector that indicates the camera angle */ 75 private static final int CA_INDICATOR_ANGLE = 40; 76 /** Length of the edge of the small sign, which indicates that traffic signs have been found in an image. */ 77 private static final int TRAFFIC_SIGN_SIZE = 6; 78 /** A third of the height of the sign, for easier calculations */ 79 private static final double TRAFFIC_SIGN_HEIGHT_3RD = Math.sqrt( 80 Math.pow(TRAFFIC_SIGN_SIZE, 2) - Math.pow(TRAFFIC_SIGN_SIZE / 2d, 2) 81 ) / 3; 75 82 76 83 private static final DataSetListenerAdapter DATASET_LISTENER = … … 102 109 } 103 110 104 /** 105 * Initializes the Layer. 106 */ 107 private void init() { 108 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 109 if (ds != null) { 110 ds.addDataSetListener(StreetsideLayer.DATASET_LISTENER); 111 } 112 MainApplication.getLayerManager().addLayer(this); 113 MainApplication.getLayerManager().addActiveLayerChangeListener(this); 114 if (!GraphicsEnvironment.isHeadless()) { 115 setMode(new SelectMode()); 116 if (StreetsideDownloader.getMode() == DOWNLOAD_MODE.OSM_AREA) { 117 StreetsideDownloader.downloadOSMArea(); 118 } 119 if (StreetsideDownloader.getMode() == DOWNLOAD_MODE.VISIBLE_AREA) { 120 mode.zoomChanged(); 121 } 122 } 123 // Does not execute when in headless mode 124 if (Main.main != null && !StreetsideMainDialog.getInstance().isShowing()) { 125 StreetsideMainDialog.getInstance().showDialog(); 126 } 127 if (StreetsidePlugin.getMapView() != null) { 128 StreetsideMainDialog.getInstance().getStreetsideImageDisplay().repaint(); 129 130 // There is no delete image action for Streetside (Mapillary functionality here removed). 131 132 //getLocationChangeset().addChangesetListener(StreetsideChangesetDialog.getInstance()); 111 /** 112 * Initializes the Layer. 113 */ 114 private void init() { 115 final DataSet ds = MainApplication.getLayerManager().getEditDataSet(); 116 if (ds != null) { 117 ds.addDataSetListener(DATASET_LISTENER); 118 } 119 MainApplication.getLayerManager().addActiveLayerChangeListener(this); 120 if (!GraphicsEnvironment.isHeadless()) { 121 setMode(new SelectMode()); 122 if (StreetsideDownloader.getMode() == DOWNLOAD_MODE.OSM_AREA) { 123 MainApplication.worker.execute(StreetsideDownloader::downloadOSMArea); 124 } 125 if (StreetsideDownloader.getMode() == DOWNLOAD_MODE.VISIBLE_AREA) { 126 mode.zoomChanged(); 127 } 128 } 129 // Does not execute when in headless mode 130 if (Main.main != null && !StreetsideMainDialog.getInstance().isShowing()) { 131 StreetsideMainDialog.getInstance().showDialog(); 132 } 133 if (StreetsidePlugin.getMapView() != null) { 134 StreetsideMainDialog.getInstance().streetsideImageDisplay.repaint(); 135 /*StreetsideMainDialog.getInstance() 136 .getInputMap(JComponent.WHEN_IN_FOCUSED_WINDOW) 137 .put(KeyStroke.getKeyStroke("DELETE"), "StreetsideDel"); 138 StreetsideMainDialog.getInstance().getActionMap() 139 .put("StreetsideDel", new DeleteImageAction());*/ 140 141 // There is no delete image action for Streetside (Streetside functionality here removed). 142 getLocationChangeset().addChangesetListener(StreetsideChangesetDialog.getInstance()); 133 143 } 134 144 createHatchTexture(); … … 136 146 } 137 147 138 public static void invalidateInstance() { 139 if (StreetsideLayer.hasInstance()) { 140 StreetsideLayer.getInstance().invalidate(); 141 } 142 } 143 144 /** 145 * Changes the mode the the given one. 146 * 147 * @param mode The mode that is going to be activated. 148 */ 149 public void setMode(AbstractMode mode) { 150 final MapView mv = StreetsidePlugin.getMapView(); 151 if (this.mode != null && mv != null) { 152 mv.removeMouseListener(this.mode); 153 mv.removeMouseMotionListener(this.mode); 154 NavigatableComponent.removeZoomChangeListener(this.mode); 155 } 156 this.mode = mode; 157 if (mode != null && mv != null) { 158 mv.setNewCursor(mode.cursor, this); 159 mv.addMouseListener(mode); 160 mv.addMouseMotionListener(mode); 161 NavigatableComponent.addZoomChangeListener(mode); 162 StreetsideUtils.updateHelpText(); 163 } 164 } 165 166 private static synchronized void clearInstance() { 167 StreetsideLayer.instance = null; 168 } 169 170 /** 171 * Returns the unique instance of this class. 172 * 173 * @return The unique instance of this class. 174 */ 175 public static synchronized StreetsideLayer getInstance() { 176 if (StreetsideLayer.instance != null) { 177 if (!MainApplication.getLayerManager().containsLayer(StreetsideLayer.instance)) { 178 MainApplication.getLayerManager().addLayer(StreetsideLayer.instance); 179 } 180 return StreetsideLayer.instance; 181 } 182 final StreetsideLayer layer = new StreetsideLayer(); 183 StreetsideLayer.instance = layer; 184 layer.init(); 185 return layer; 186 } 187 188 /** 189 * @return if the unique instance of this layer is currently instantiated and added to the {@link LayerManager} 190 */ 191 public static boolean hasInstance() { 192 return StreetsideLayer.instance != null && MainApplication.getLayerManager().containsLayer(StreetsideLayer.instance); 193 } 148 public static void invalidateInstance() { 149 if (hasInstance()) { 150 getInstance().invalidate(); 151 } 152 } 153 154 /** 155 * Changes the mode the the given one. 156 * 157 * @param mode The mode that is going to be activated. 158 */ 159 public void setMode(AbstractMode mode) { 160 final MapView mv = StreetsidePlugin.getMapView(); 161 if (this.mode != null && mv != null) { 162 mv.removeMouseListener(this.mode); 163 mv.removeMouseMotionListener(this.mode); 164 NavigatableComponent.removeZoomChangeListener(this.mode); 165 } 166 this.mode = mode; 167 if (mode != null && mv != null) { 168 mv.setNewCursor(mode.cursor, this); 169 mv.addMouseListener(mode); 170 mv.addMouseMotionListener(mode); 171 NavigatableComponent.addZoomChangeListener(mode); 172 StreetsideUtils.updateHelpText(); 173 } 174 } 175 176 private static synchronized void clearInstance() { 177 instance = null; 178 } 179 180 /** 181 * Returns the unique instance of this class. 182 * 183 * @return The unique instance of this class. 184 */ 185 public static synchronized StreetsideLayer getInstance() { 186 if (instance != null) { 187 return instance; 188 } 189 final StreetsideLayer layer = new StreetsideLayer(); 190 layer.init(); 191 instance = layer; // Only set instance field after initialization is complete 192 return instance; 193 } 194 195 /** 196 * @return if the unique instance of this layer is currently instantiated 197 */ 198 public static boolean hasInstance() { 199 return instance != null; 200 } 194 201 195 202 /** … … 200 207 */ 201 208 public StreetsideData getData() { 202 return data;209 return this.data; 203 210 } 204 211 205 /** 206 * Returns the n-nearest image, for n=1 the nearest one is returned, for n=2 the second nearest one and so on. 207 * The "n-nearest image" is picked from the list of one image from every sequence that is nearest to the currently 208 * selected image, excluding the sequence to which the selected image belongs. 209 * @param n the index for picking from the list of "nearest images", beginning from 1 210 * @return the n-nearest image to the currently selected image 211 */ 212 public synchronized StreetsideImage getNNearestImage(final int n) { 213 return n >= 1 && n <= nearestImages.length ? nearestImages[n - 1] : null; 214 } 215 216 /** 217 * Returns the {@link StreetsideLocationChangeset} object, which acts as the database of the 218 * Layer. 219 * 220 * @return The {@link StreetsideData} object that stores the database. 221 */ 222 public StreetsideLocationChangeset getLocationChangeset() { 223 return locationChangeset; 224 } 212 /** 213 * Returns the {@link StreetsideLocationChangeset} object, which acts as the database of the 214 * Layer. 215 * 216 * @return The {@link StreetsideData} object that stores the database. 217 */ 218 public StreetsideLocationChangeset getLocationChangeset() { 219 return locationChangeset; 220 } 221 222 /** 223 * Returns the n-nearest image, for n=1 the nearest one is returned, for n=2 the second nearest one and so on. 224 * The "n-nearest image" is picked from the list of one image from every sequence that is nearest to the currently 225 * selected image, excluding the sequence to which the selected image belongs. 226 * @param n the index for picking from the list of "nearest images", beginning from 1 227 * @return the n-nearest image to the currently selected image 228 */ 229 public synchronized StreetsideImage getNNearestImage(final int n) { 230 return n >= 1 && n <= nearestImages.length ? nearestImages[n - 1] : null; 231 } 232 233 @Override 234 public synchronized void destroy() { 235 clearInstance(); 236 setMode(null); 237 StreetsideRecord.getInstance().reset(); 238 AbstractMode.resetThread(); 239 StreetsideDownloader.stopAll(); 240 if (StreetsideMainDialog.hasInstance()) { 241 StreetsideMainDialog.getInstance().setImage(null); 242 StreetsideMainDialog.getInstance().updateImage(); 243 } 244 final MapView mv = StreetsidePlugin.getMapView(); 245 if (mv != null) { 246 mv.removeMouseListener(mode); 247 mv.removeMouseMotionListener(mode); 248 } 249 try { 250 MainApplication.getLayerManager().removeActiveLayerChangeListener(this); 251 if (MainApplication.getLayerManager().getEditDataSet() != null) { 252 MainApplication.getLayerManager().getEditDataSet().removeDataSetListener(DATASET_LISTENER); 253 } 254 } catch (IllegalArgumentException e) { 255 // TODO: It would be ideal, to fix this properly. But for the moment let's catch this, for when a listener has already been removed. 256 } 257 super.destroy(); 258 } 225 259 226 260 227 261 @Override 228 public synchronized void destroy() { 229 // TODO: Add destroy code for CubemapBuilder, et al.? @rrh 230 StreetsideLayer.clearInstance(); 231 setMode(null); 232 StreetsideRecord.getInstance().reset(); 233 AbstractMode.resetThread(); 234 StreetsideDownloader.stopAll(); 235 if (StreetsideMainDialog.hasInstance()) { 236 StreetsideMainDialog.getInstance().setImage(null); 237 StreetsideMainDialog.getInstance().updateImage(); 238 } 239 final MapView mv = StreetsidePlugin.getMapView(); 240 if (mv != null) { 241 mv.removeMouseListener(mode); 242 mv.removeMouseMotionListener(mode); 243 } 244 try { 245 MainApplication.getLayerManager().removeActiveLayerChangeListener(this); 246 if (MainApplication.getLayerManager().getEditDataSet() != null) { 247 MainApplication.getLayerManager().getEditDataSet().removeDataSetListener(StreetsideLayer.DATASET_LISTENER); 248 } 249 } catch (final IllegalArgumentException e) { 250 // TODO: It would be ideal, to fix this properly. But for the moment let's catch this, for when a listener has already been removed. 251 } 252 super.destroy(); 253 } 254 255 @Override 256 public boolean isModified() { 257 // TODO: Add cubemap modification here? @rrh 258 return data.getImages().parallelStream().anyMatch(StreetsideAbstractImage::isModified); 259 } 260 261 @Override 262 public void setVisible(boolean visible) { 263 super.setVisible(visible); 264 getData().getImages().parallelStream().forEach(img -> img.setVisible(visible)); 265 if (MainApplication.getMap() != null) { 266 //StreetsideFilterDialog.getInstance().refresh(); 267 } 268 } 269 270 /** 271 * Initialize the hatch pattern used to paint the non-downloaded area. 272 */ 273 private void createHatchTexture() { 274 final BufferedImage bi = new BufferedImage(15, 15, BufferedImage.TYPE_INT_ARGB); 275 final Graphics2D big = bi.createGraphics(); 276 big.setColor(StreetsideProperties.BACKGROUND.get()); 277 final Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); 278 big.setComposite(comp); 279 big.fillRect(0, 0, 15, 15); 280 big.setColor(StreetsideProperties.OUTSIDE_DOWNLOADED_AREA.get()); 281 big.drawLine(0, 15, 15, 0); 282 final Rectangle r = new Rectangle(0, 0, 15, 15); 283 hatched = new TexturePaint(bi, r); 284 } 285 286 @Override 287 public synchronized void paint(final Graphics2D g, final MapView mv, final Bounds box) { 288 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 289 if (MainApplication.getLayerManager().getActiveLayer() == this) { 290 // paint remainder 291 g.setPaint(hatched); 292 g.fill(MapViewGeometryUtil.getNonDownloadedArea(mv, data.getBounds())); 293 } 294 295 // Draw the blue and red line 296 synchronized (StreetsideLayer.class) { 297 final StreetsideAbstractImage selectedImg = data.getSelectedImage(); 298 for (int i = 0; i < nearestImages.length && selectedImg != null; i++) { 299 if (i == 0) { 300 g.setColor(Color.RED); 301 } else { 302 g.setColor(Color.BLUE); 303 } 304 final Point selected = mv.getPoint(selectedImg.getMovingLatLon()); 305 final Point p = mv.getPoint(nearestImages[i].getMovingLatLon()); 306 g.draw(new Line2D.Double(p.getX(), p.getY(), selected.getX(), selected.getY())); 307 } 308 } 309 310 // Draw sequence line 311 g.setStroke(new BasicStroke(2)); 312 final StreetsideAbstractImage selectedImage = getData().getSelectedImage(); 313 for (final StreetsideSequence seq : getData().getSequences()) { 314 if (seq.getImages().contains(selectedImage)) { 315 g.setColor( 316 seq.getId() == null ? StreetsideColorScheme.SEQ_IMPORTED_SELECTED : StreetsideColorScheme.SEQ_SELECTED 317 ); 318 } else { 319 g.setColor( 320 seq.getId() == null ? StreetsideColorScheme.SEQ_IMPORTED_UNSELECTED : StreetsideColorScheme.SEQ_UNSELECTED 321 ); 322 } 323 g.draw(MapViewGeometryUtil.getSequencePath(mv, seq)); 324 } 325 /*for (final StreetsideAbstractImage imageAbs : data.getImages()) { 326 if (imageAbs.isVisible() && mv != null && mv.contains(mv.getPoint(imageAbs.getMovingLatLon()))) { 327 drawImageMarker(g, imageAbs); 328 } 329 }*/ 330 if (mode instanceof JoinMode) { 331 mode.paint(g, mv, box); 332 } 333 } 334 335 /* 336 * Draws an image marker onto the given Graphics context. 337 * @param g the Graphics context 338 * @param img the image to be drawn onto the Graphics context 339 */ 340 /*private void drawImageMarker(final Graphics2D g, final StreetsideAbstractImage img) { 341 if (img == null || img.getLatLon() == null) { 342 Logging.warn("An image is not painted, because it is null or has no LatLon!"); 343 return; 344 } 345 final StreetsideAbstractImage selectedImg = getData().getSelectedImage(); 346 final Point p = MainApplication.getMap().mapView.getPoint(img.getMovingLatLon()); 347 348 // Determine colors 349 final Color markerC; 350 final Color directionC; 351 if (selectedImg != null && getData().getMultiSelectedImages().contains(img)) { 352 markerC = img instanceof StreetsideImportedImage 353 ? StreetsideColorScheme.SEQ_IMPORTED_HIGHLIGHTED 354 : StreetsideColorScheme.SEQ_HIGHLIGHTED; 355 directionC = img instanceof StreetsideImportedImage 356 ? StreetsideColorScheme.SEQ_IMPORTED_HIGHLIGHTED_CA 357 : StreetsideColorScheme.SEQ_HIGHLIGHTED_CA; 358 } else if (selectedImg != null && selectedImg.getSequence() != null && selectedImg.getSequence().equals(img.getSequence())) { 359 markerC = img instanceof StreetsideImportedImage 360 ? StreetsideColorScheme.SEQ_IMPORTED_SELECTED 361 : StreetsideColorScheme.SEQ_SELECTED; 362 directionC = img instanceof StreetsideImportedImage 363 ? StreetsideColorScheme.SEQ_IMPORTED_SELECTED_CA 364 : StreetsideColorScheme.SEQ_SELECTED_CA; 365 } else { 366 markerC = img instanceof StreetsideImportedImage 367 ? StreetsideColorScheme.SEQ_IMPORTED_UNSELECTED 368 : StreetsideColorScheme.SEQ_UNSELECTED; 369 directionC = img instanceof StreetsideImportedImage 370 ? StreetsideColorScheme.SEQ_IMPORTED_UNSELECTED_CA 371 : StreetsideColorScheme.SEQ_UNSELECTED_CA; 372 } 373 374 // Paint direction indicator 375 g.setColor(directionC); 376 g.fillArc(p.x - StreetsideLayer.CA_INDICATOR_RADIUS, p.y - StreetsideLayer.CA_INDICATOR_RADIUS, 2 * StreetsideLayer.CA_INDICATOR_RADIUS, 2 * StreetsideLayer.CA_INDICATOR_RADIUS, (int) (90 - img.getMovingHe() - StreetsideLayer.CA_INDICATOR_ANGLE / 2d), StreetsideLayer.CA_INDICATOR_ANGLE); 377 // Paint image marker 378 g.setColor(markerC); 379 g.fillOval(p.x - StreetsideLayer.IMG_MARKER_RADIUS, p.y - StreetsideLayer.IMG_MARKER_RADIUS, 2 * StreetsideLayer.IMG_MARKER_RADIUS, 2 * StreetsideLayer.IMG_MARKER_RADIUS); 380 381 // Paint highlight for selected or highlighted images 382 if (img.equals(getData().getHighlightedImage()) || getData().getMultiSelectedImages().contains(img)) { 383 g.setColor(Color.WHITE); 384 g.setStroke(new BasicStroke(2)); 385 g.drawOval(p.x - StreetsideLayer.IMG_MARKER_RADIUS, p.y - StreetsideLayer.IMG_MARKER_RADIUS, 2 * StreetsideLayer.IMG_MARKER_RADIUS, 2 * StreetsideLayer.IMG_MARKER_RADIUS); 386 } 387 388 // TODO: reimplement detections for Bing Metadata? RRH 389 if (img instanceof StreetsideImage && !((StreetsideImage) img).getDetections().isEmpty()) { 262 public boolean isModified() { 263 return this.data.getImages().parallelStream().anyMatch(StreetsideAbstractImage::isModified); 264 } 265 266 @Override 267 public void setVisible(boolean visible) { 268 super.setVisible(visible); 269 getData().getImages().parallelStream().forEach(img -> img.setVisible(visible)); 270 if (MainApplication.getMap() != null) { 271 //StreetsideFilterDialog.getInstance().refresh(); 272 } 273 } 274 275 /** 276 * Initialize the hatch pattern used to paint the non-downloaded area. 277 */ 278 private void createHatchTexture() { 279 BufferedImage bi = new BufferedImage(15, 15, BufferedImage.TYPE_INT_ARGB); 280 Graphics2D big = bi.createGraphics(); 281 big.setColor(StreetsideProperties.BACKGROUND.get()); 282 Composite comp = AlphaComposite.getInstance(AlphaComposite.SRC_OVER, 0.3f); 283 big.setComposite(comp); 284 big.fillRect(0, 0, 15, 15); 285 big.setColor(StreetsideProperties.OUTSIDE_DOWNLOADED_AREA.get()); 286 big.drawLine(0, 15, 15, 0); 287 Rectangle r = new Rectangle(0, 0, 15, 15); 288 this.hatched = new TexturePaint(bi, r); 289 } 290 291 @Override 292 public synchronized void paint(final Graphics2D g, final MapView mv, final Bounds box) { 293 g.setRenderingHint(RenderingHints.KEY_ANTIALIASING, RenderingHints.VALUE_ANTIALIAS_ON); 294 if (MainApplication.getLayerManager().getActiveLayer() == this) { 295 // paint remainder 296 g.setPaint(hatched); 297 g.fill(MapViewGeometryUtil.getNonDownloadedArea(mv, this.data.getBounds())); 298 } 299 300 // Draw the blue and red line 301 synchronized (StreetsideLayer.class) { 302 final StreetsideAbstractImage selectedImg = data.getSelectedImage(); 303 for (int i = 0; i < nearestImages.length && selectedImg != null; i++) { 304 if (i == 0) { 305 g.setColor(Color.RED); 306 } else { 307 g.setColor(Color.BLUE); 308 } 309 final Point selected = mv.getPoint(selectedImg.getMovingLatLon()); 310 final Point p = mv.getPoint(nearestImages[i].getMovingLatLon()); 311 g.draw(new Line2D.Double(p.getX(), p.getY(), selected.getX(), selected.getY())); 312 } 313 } 314 315 // Draw sequence line 316 g.setStroke(new BasicStroke(2)); 317 final StreetsideAbstractImage selectedImage = getData().getSelectedImage(); 318 for (StreetsideSequence seq : getData().getSequences()) { 319 if (seq.getImages().contains(selectedImage)) { 320 g.setColor( 321 seq.getId() == null ? StreetsideColorScheme.SEQ_IMPORTED_SELECTED : StreetsideColorScheme.SEQ_SELECTED 322 ); 323 } else { 324 g.setColor( 325 seq.getId() == null ? StreetsideColorScheme.SEQ_IMPORTED_UNSELECTED : StreetsideColorScheme.SEQ_UNSELECTED 326 ); 327 } 328 g.draw(MapViewGeometryUtil.getSequencePath(mv, seq)); 329 } 330 for (StreetsideAbstractImage imageAbs : this.data.getImages()) { 331 if (imageAbs.isVisible() && mv != null && mv.contains(mv.getPoint(imageAbs.getMovingLatLon()))) { 332 drawImageMarker(g, imageAbs); 333 } 334 } 335 if (this.mode instanceof JoinMode) { 336 this.mode.paint(g, mv, box); 337 } 338 } 339 340 /** 341 * Draws an image marker onto the given Graphics context. 342 * @param g the Graphics context 343 * @param img the image to be drawn onto the Graphics context 344 */ 345 private void drawImageMarker(final Graphics2D g, final StreetsideAbstractImage img) { 346 if (img == null || img.getLatLon() == null) { 347 Logging.warn("An image is not painted, because it is null or has no LatLon!"); 348 return; 349 } 350 final StreetsideAbstractImage selectedImg = getData().getSelectedImage(); 351 final Point p = MainApplication.getMap().mapView.getPoint(img.getMovingLatLon()); 352 353 // Determine colors 354 final Color markerC; 355 final Color directionC; 356 if (selectedImg != null && getData().getMultiSelectedImages().contains(img)) { 357 markerC = img instanceof StreetsideImportedImage 358 ? StreetsideColorScheme.SEQ_IMPORTED_HIGHLIGHTED 359 : StreetsideColorScheme.SEQ_HIGHLIGHTED; 360 directionC = img instanceof StreetsideImportedImage 361 ? StreetsideColorScheme.SEQ_IMPORTED_HIGHLIGHTED_CA 362 : StreetsideColorScheme.SEQ_HIGHLIGHTED_CA; 363 } else if (selectedImg != null && selectedImg.getSequence() != null && selectedImg.getSequence().equals(img.getSequence())) { 364 markerC = img instanceof StreetsideImportedImage 365 ? StreetsideColorScheme.SEQ_IMPORTED_SELECTED 366 : StreetsideColorScheme.SEQ_SELECTED; 367 directionC = img instanceof StreetsideImportedImage 368 ? StreetsideColorScheme.SEQ_IMPORTED_SELECTED_CA 369 : StreetsideColorScheme.SEQ_SELECTED_CA; 370 } else { 371 markerC = img instanceof StreetsideImportedImage 372 ? StreetsideColorScheme.SEQ_IMPORTED_UNSELECTED 373 : StreetsideColorScheme.SEQ_UNSELECTED; 374 directionC = img instanceof StreetsideImportedImage 375 ? StreetsideColorScheme.SEQ_IMPORTED_UNSELECTED_CA 376 : StreetsideColorScheme.SEQ_UNSELECTED_CA; 377 } 378 379 // Paint direction indicator 380 g.setColor(directionC); 381 g.fillArc(p.x - CA_INDICATOR_RADIUS, p.y - CA_INDICATOR_RADIUS, 2 * CA_INDICATOR_RADIUS, 2 * CA_INDICATOR_RADIUS, (int) (90 - img.getMovingHe() - CA_INDICATOR_ANGLE / 2d), CA_INDICATOR_ANGLE); 382 // Paint image marker 383 g.setColor(markerC); 384 g.fillOval(p.x - IMG_MARKER_RADIUS, p.y - IMG_MARKER_RADIUS, 2 * IMG_MARKER_RADIUS, 2 * IMG_MARKER_RADIUS); 385 386 // Paint highlight for selected or highlighted images 387 if (img.equals(getData().getHighlightedImage()) || getData().getMultiSelectedImages().contains(img)) { 388 g.setColor(Color.WHITE); 389 g.setStroke(new BasicStroke(2)); 390 g.drawOval(p.x - IMG_MARKER_RADIUS, p.y - IMG_MARKER_RADIUS, 2 * IMG_MARKER_RADIUS, 2 * IMG_MARKER_RADIUS); 391 } 392 393 394 /*if (img instanceof StreetsideImage && !((StreetsideImage) img).getDetections().isEmpty()) { 390 395 final Path2D trafficSign = new Path2D.Double(); 391 396 trafficSign.moveTo(p.getX() - StreetsideLayer.TRAFFIC_SIGN_SIZE / 2d, p.getY() - StreetsideLayer.TRAFFIC_SIGN_HEIGHT_3RD); … … 398 403 g.setColor(Color.RED); 399 404 g.draw(trafficSign); 400 } 401 }*/ 402 403 @Override 404 public Icon getIcon() { 405 return StreetsidePlugin.LOGO.setSize(ImageSizes.LAYER).get(); 405 }*/ 406 406 } 407 407 408 @Override 409 public boolean isMergable(Layer other) { 410 return false; 411 } 412 413 @Override 414 public void mergeFrom(Layer from) { 415 throw new UnsupportedOperationException( 416 "This layer does not support merging yet"); 417 } 418 419 @Override 420 public Action[] getMenuEntries() { 421 return new Action[]{ 422 LayerListDialog.getInstance().createShowHideLayerAction(), 423 LayerListDialog.getInstance().createDeleteLayerAction(), 424 new LayerListPopup.InfoAction(this) 425 }; 426 } 427 428 @Override 429 public Object getInfoComponent() { 430 final IntSummaryStatistics seqSizeStats = getData().getSequences().stream().mapToInt(seq -> seq.getImages().size()).summaryStatistics(); 431 return new StringBuilder(I18n.tr("Streetside layer")) 432 .append("\n") 433 .append(I18n.tr( 434 "{0} sequences, each containing between {1} and {2} images (ø {3})", 435 getData().getSequences().size(), 436 seqSizeStats.getCount() <= 0 ? 0 : seqSizeStats.getMin(), 437 seqSizeStats.getCount() <= 0 ? 0 : seqSizeStats.getMax(), 438 seqSizeStats.getAverage() 439 )) 440 .append("\n\n") 441 .append(I18n.tr( 442 "{0} imported images", 443 getData().getImages().stream().filter(i -> i instanceof StreetsideImportedImage).count() 444 )) 445 .append("\n+ ") 446 .append(I18n.tr( 447 "{0} downloaded images", 448 getData().getImages().stream().filter(i -> i instanceof StreetsideImage).count() 449 )) 450 .append("\n= ") 451 .append(I18n.tr( 452 "{0} images in total", 453 getData().getImages().size() 454 )).toString(); 455 } 456 457 @Override 458 public String getToolTipText() { 459 return I18n.tr("{0} images in {1} sequences", getData().getImages().size(), getData().getSequences().size()); 460 } 461 462 @Override 463 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) { 464 if (MainApplication.getLayerManager().getActiveLayer() == this) { 465 StreetsideUtils.updateHelpText(); 466 } 467 468 if (MainApplication.getLayerManager().getEditLayer() != e.getPreviousDataLayer()) { 469 if (MainApplication.getLayerManager().getEditLayer() != null) { 470 MainApplication.getLayerManager().getEditLayer().getDataSet().addDataSetListener(StreetsideLayer.DATASET_LISTENER); 471 } 472 if (e.getPreviousDataLayer() != null) { 473 e.getPreviousDataLayer().getDataSet().removeDataSetListener(StreetsideLayer.DATASET_LISTENER); 474 } 475 } 476 } 477 478 @Override 479 public void visitBoundingBox(BoundingXYVisitor v) { 480 } 481 482 /* (non-Javadoc) 483 * @see org.openstreetmap.josm.plugins.streetside.StreetsideDataListener#imagesAdded() 484 */ 485 @Override 486 public void imagesAdded() { 487 // TODO: Never used - could this be of use? @rrh 488 updateNearestImages(); 489 } 490 491 /* (non-Javadoc) 492 * @see org.openstreetmap.josm.plugins.mapillary.StreetsideDataListener#selectedImageChanged(org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage, org.openstreetmap.josm.plugins.mapillary.MapillaryAbstractImage) 493 */ 494 @Override 495 public void selectedImageChanged(StreetsideAbstractImage oldImage, StreetsideAbstractImage newImage) { 496 updateNearestImages(); 497 } 498 499 /** 500 * Returns the closest images belonging to a different sequence and 501 * different from the specified target image. 502 * 503 * @param target the image for which you want to find the nearest other images 504 * @param limit the maximum length of the returned array 505 * @return An array containing the closest images belonging to different sequences sorted by distance from target. 506 */ 507 private StreetsideImage[] getNearestImagesFromDifferentSequences(StreetsideAbstractImage target, int limit) { 508 return data.getSequences().parallelStream() 509 .filter(seq -> seq.getId() != null && !seq.getId().equals(target.getSequence().getId())) 510 .map(seq -> { // Maps sequence to image from sequence that is nearest to target 511 final Optional<StreetsideAbstractImage> resImg = seq.getImages().parallelStream() 512 .filter(img -> img instanceof StreetsideImage && img.isVisible()) 513 .min(new NearestImgToTargetComparator(target)); 514 return resImg.orElse(null); 515 }) 516 .filter(img -> // Filters out images too far away from target 517 img != null && 518 img.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) 519 < StreetsideProperties.SEQUENCE_MAX_JUMP_DISTANCE.get() 520 ) 521 .sorted(new NearestImgToTargetComparator(target)) 522 .limit(limit) 523 .toArray(StreetsideImage[]::new); 524 } 525 526 /* 527 * Returns the closest images belonging to a different sequence and 528 * different from the specified target image. 529 * 530 * @param target the image for which you want to find the nearest other images 531 * @param limit the maximum length of the returned array 532 * @return An array containing the closest images belonging to different sequences sorted by distance from target. 533 */ 534 /*private StreetsideCubemap[] getNearestCubemapsFromDifferentSequences(StreetsideAbstractImage target, int limit) { 535 return data.getSequences().parallelStream() 536 .filter(seq -> seq.getId() != null && !seq.getId().equals(target.getSequence().getId())) 537 .map(seq -> { // Maps sequence to image from sequence that is nearest to target 538 final Optional<StreetsideAbstractImage> resCb = seq.getImages().parallelStream() 539 .filter(cb -> cb instanceof StreetsideCubemap && cb.isVisible()) 540 .min(new NearestCbToTargetComparator(target)); 541 return resCb.orElse(null); 542 }) 543 .filter(cb -> // Filters out images too far away from target 544 cb != null && 545 cb.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) 546 < StreetsideProperties.SEQUENCE_MAX_JUMP_DISTANCE.get() 547 ) 548 .sorted(new NearestCbToTargetComparator(target)) 549 .limit(limit) 550 .toArray(StreetsideCubemap[]::new); 551 }*/ 552 553 private synchronized void updateNearestImages() { 554 final StreetsideAbstractImage selected = data.getSelectedImage(); 555 if (selected != null) { 556 // TODO: could this be used to pre-cache cubemaps? @rrh 557 nearestImages = getNearestImagesFromDifferentSequences(selected, 2); 558 } else { 559 nearestImages = new StreetsideImage[0]; 560 } 561 if (MainApplication.isDisplayingMapView()) { 562 StreetsideMainDialog.getInstance().redButton.setEnabled(nearestImages.length >= 1); 563 StreetsideMainDialog.getInstance().blueButton.setEnabled(nearestImages.length >= 2); 564 } 565 if (nearestImages.length >= 1) { 566 CacheUtils.downloadPicture(nearestImages[0]); 567 // TODO: download/pre-caches cubemaps here? 568 //CacheUtils.downloadCubemap(nearestImages[0]); 569 if (nearestImages.length >= 2) { 570 CacheUtils.downloadPicture(nearestImages[1]); 571 // TODO: download/pre-caches cubemaps here? 572 //CacheUtils.downloadCubemap(nearestImages[1]); 573 } 574 } 575 } 576 577 private static class NearestImgToTargetComparator implements Comparator<StreetsideAbstractImage> { 578 private final StreetsideAbstractImage target; 579 580 public NearestImgToTargetComparator(StreetsideAbstractImage target) { 581 this.target = target; 582 } 583 /* (non-Javadoc) 584 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 585 */ 586 @Override 587 public int compare(StreetsideAbstractImage img1, StreetsideAbstractImage img2) { 588 return (int) Math.signum( 589 img1.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) - 590 img2.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) 591 ); 592 } 593 } 594 595 private static class NearestCbToTargetComparator implements Comparator<StreetsideAbstractImage> { 596 private final StreetsideAbstractImage target; 597 598 public NearestCbToTargetComparator(StreetsideAbstractImage target) { 599 this.target = target; 600 } 601 /* (non-Javadoc) 602 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 603 */ 604 @Override 605 public int compare(StreetsideAbstractImage img1, StreetsideAbstractImage img2) { 606 return (int) Math.signum( 607 img1.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) - 608 img2.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) 609 ); 610 } 611 } 408 @Override 409 public Icon getIcon() { 410 return StreetsidePlugin.LOGO.setSize(ImageSizes.LAYER).get(); 411 } 412 413 @Override 414 public boolean isMergable(Layer other) { 415 return false; 416 } 417 418 @Override 419 public void mergeFrom(Layer from) { 420 throw new UnsupportedOperationException( 421 "This layer does not support merging yet"); 422 } 423 424 @Override 425 public Action[] getMenuEntries() { 426 return new Action[]{ 427 LayerListDialog.getInstance().createShowHideLayerAction(), 428 LayerListDialog.getInstance().createDeleteLayerAction(), 429 new LayerListPopup.InfoAction(this) 430 }; 431 } 432 433 @Override 434 public Object getInfoComponent() { 435 IntSummaryStatistics seqSizeStats = getData().getSequences().stream().mapToInt(seq -> seq.getImages().size()).summaryStatistics(); 436 return new StringBuilder(I18n.tr("Streetside layer")) 437 .append('\n') 438 .append(I18n.tr( 439 "{0} sequences, each containing between {1} and {2} images (ø {3})", 440 getData().getSequences().size(), 441 seqSizeStats.getCount() <= 0 ? 0 : seqSizeStats.getMin(), 442 seqSizeStats.getCount() <= 0 ? 0 : seqSizeStats.getMax(), 443 seqSizeStats.getAverage() 444 )) 445 .append("\n\n") 446 .append(I18n.tr( 447 "{0} imported images", 448 getData().getImages().stream().filter(i -> i instanceof StreetsideImportedImage).count() 449 )) 450 .append("\n+ ") 451 .append(I18n.tr( 452 "{0} downloaded images", 453 getData().getImages().stream().filter(i -> i instanceof StreetsideImage).count() 454 )) 455 .append("\n= ") 456 .append(I18n.tr( 457 "{0} images in total", 458 getData().getImages().size() 459 )).toString(); 460 } 461 462 @Override 463 public String getToolTipText() { 464 return I18n.tr("{0} images in {1} sequences", getData().getImages().size(), getData().getSequences().size()); 465 } 466 467 @Override 468 public void activeOrEditLayerChanged(ActiveLayerChangeEvent e) { 469 if (MainApplication.getLayerManager().getActiveLayer() == this) { 470 StreetsideUtils.updateHelpText(); 471 } 472 473 if (MainApplication.getLayerManager().getEditLayer() != e.getPreviousDataLayer()) { 474 if (MainApplication.getLayerManager().getEditLayer() != null) { 475 MainApplication.getLayerManager().getEditLayer().getDataSet().addDataSetListener(DATASET_LISTENER); 476 } 477 if (e.getPreviousDataLayer() != null) { 478 e.getPreviousDataLayer().getDataSet().removeDataSetListener(DATASET_LISTENER); 479 } 480 } 481 } 482 483 @Override 484 public void visitBoundingBox(BoundingXYVisitor v) { 485 } 486 487 /* (non-Javadoc) 488 * @see org.openstreetmap.josm.plugins.streetside.StreetsideDataListener#imagesAdded() 489 */ 490 @Override 491 public void imagesAdded() { 492 updateNearestImages(); 493 } 494 495 /* (non-Javadoc) 496 * @see org.openstreetmap.josm.plugins.streetside.StreetsideDataListener#selectedImageChanged(org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage, org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage) 497 */ 498 @Override 499 public void selectedImageChanged(StreetsideAbstractImage oldImage, StreetsideAbstractImage newImage) { 500 updateNearestImages(); 501 } 502 503 /** 504 * Returns the closest images belonging to a different sequence and 505 * different from the specified target image. 506 * 507 * @param target the image for which you want to find the nearest other images 508 * @param limit the maximum length of the returned array 509 * @return An array containing the closest images belonging to different sequences sorted by distance from target. 510 */ 511 private StreetsideImage[] getNearestImagesFromDifferentSequences(StreetsideAbstractImage target, int limit) { 512 return data.getSequences().parallelStream() 513 .filter(seq -> seq.getId() != null && !seq.getId().equals(target.getSequence().getId())) 514 .map(seq -> { // Maps sequence to image from sequence that is nearest to target 515 Optional<StreetsideAbstractImage> resImg = seq.getImages().parallelStream() 516 .filter(img -> img instanceof StreetsideImage && img.isVisible()) 517 .min(new NearestImgToTargetComparator(target)); 518 return resImg.orElse(null); 519 }) 520 .filter(img -> // Filters out images too far away from target 521 img != null && 522 img.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) 523 < StreetsideProperties.SEQUENCE_MAX_JUMP_DISTANCE.get() 524 ) 525 .sorted(new NearestImgToTargetComparator(target)) 526 .limit(limit) 527 .toArray(StreetsideImage[]::new); 528 } 529 530 private synchronized void updateNearestImages() { 531 final StreetsideAbstractImage selected = data.getSelectedImage(); 532 if (selected != null) { 533 nearestImages = getNearestImagesFromDifferentSequences(selected, 2); 534 } else { 535 nearestImages = new StreetsideImage[0]; 536 } 537 if (MainApplication.isDisplayingMapView()) { 538 StreetsideMainDialog.getInstance().redButton.setEnabled(nearestImages.length >= 1); 539 StreetsideMainDialog.getInstance().blueButton.setEnabled(nearestImages.length >= 2); 540 } 541 if (nearestImages.length >= 1) { 542 CacheUtils.downloadPicture(nearestImages[0]); 543 if (nearestImages.length >= 2) { 544 CacheUtils.downloadPicture(nearestImages[1]); 545 } 546 } 547 } 548 549 /** 550 * Action used to delete images. 551 * 552 * @author nokutu 553 */ 554 /*private class DeleteImageAction extends AbstractAction { 555 556 private static final long serialVersionUID = -982809854631863962L; 557 558 @Override 559 public void actionPerformed(ActionEvent e) { 560 if (instance != null) 561 StreetsideRecord.getInstance().addCommand( 562 new CommandDelete(getData().getMultiSelectedImages())); 563 } 564 }*/ 565 566 private static class NearestImgToTargetComparator implements Comparator<StreetsideAbstractImage> { 567 private final StreetsideAbstractImage target; 568 569 public NearestImgToTargetComparator(StreetsideAbstractImage target) { 570 this.target = target; 571 } 572 /* (non-Javadoc) 573 * @see java.util.Comparator#compare(java.lang.Object, java.lang.Object) 574 */ 575 @Override 576 public int compare(StreetsideAbstractImage img1, StreetsideAbstractImage img2) { 577 return (int) Math.signum( 578 img1.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) - 579 img2.getMovingLatLon().greatCircleDistance(target.getMovingLatLon()) 580 ); 581 } 582 } 612 583 } -
applications/editors/josm/plugins/MicrosoftStreetside/src/org/openstreetmap/josm/plugins/streetside/StreetsidePlugin.java
r34325 r34329 49 49 MainMenu.add(MainApplication.getMenu().moreToolsMenu, WALK_ACTION, false); 50 50 //MainMenu.add(MainApplication.getMenu().imagerySubMenu, new MapObjectLayerAction(), false); 51 //MainMenu.add(MainApplication.getMenu().imagerySubMenu, new MapObjectLayerAction(), false); 51 52 } 52 53 } … … 67 68 68 69 static StreetsideDataListener[] getStreetsideDataListeners() { 69 return new StreetsideDataListener[]{ /*UPLOAD_ACTION,*/WALK_ACTION, ZOOM_ACTION, CubemapBuilder.getInstance()};70 return new StreetsideDataListener[]{WALK_ACTION, ZOOM_ACTION, CubemapBuilder.getInstance()}; 70 71 } 71 72
Note:
See TracChangeset
for help on using the changeset viewer.