001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.plugins.streetside.mode; 003 004import java.awt.Cursor; 005import java.awt.Graphics2D; 006import java.awt.Point; 007import java.awt.event.MouseAdapter; 008import java.util.Calendar; 009 010import org.openstreetmap.josm.data.Bounds; 011import org.openstreetmap.josm.gui.MainApplication; 012import org.openstreetmap.josm.gui.MapView; 013import org.openstreetmap.josm.gui.NavigatableComponent.ZoomChangeListener; 014import org.openstreetmap.josm.plugins.streetside.StreetsideAbstractImage; 015import org.openstreetmap.josm.plugins.streetside.StreetsideLayer; 016import org.openstreetmap.josm.plugins.streetside.io.download.StreetsideDownloader; 017 018/** 019 * Superclass for all the mode of the {@link StreetsideLayer}. 020 * 021 * @author nokutu 022 * @see StreetsideLayer 023 */ 024public abstract class AbstractMode extends MouseAdapter implements 025 ZoomChangeListener { 026 027 private static final int DOWNLOAD_COOLDOWN = 2000; 028 private static SemiautomaticThread semiautomaticThread = new SemiautomaticThread(); 029 030 /** 031 * Cursor that should become active when this mode is activated. 032 */ 033 public int cursor = Cursor.DEFAULT_CURSOR; 034 035 protected StreetsideAbstractImage getClosest(Point clickPoint) { 036 double snapDistance = 10; 037 double minDistance = Double.MAX_VALUE; 038 StreetsideAbstractImage closest = null; 039 for (StreetsideAbstractImage image : StreetsideLayer.getInstance().getData().getImages()) { 040 Point imagePoint = MainApplication.getMap().mapView.getPoint(image.getMovingLatLon()); 041 imagePoint.setLocation(imagePoint.getX(), imagePoint.getY()); 042 double dist = clickPoint.distanceSq(imagePoint); 043 if (minDistance > dist && clickPoint.distance(imagePoint) < snapDistance 044 && image.isVisible()) { 045 minDistance = dist; 046 closest = image; 047 } 048 } 049 return closest; 050 } 051 052 /** 053 * Paint the dataset using the engine set. 054 * 055 * @param g {@link Graphics2D} used for painting 056 * @param mv The object that can translate GeoPoints to screen coordinates. 057 * @param box Area where painting is going to be performed 058 */ 059 public abstract void paint(Graphics2D g, MapView mv, Bounds box); 060 061 @Override 062 public void zoomChanged() { 063 if (StreetsideDownloader.getMode() == StreetsideDownloader.DOWNLOAD_MODE.VISIBLE_AREA) { 064 if (!semiautomaticThread.isAlive()) 065 semiautomaticThread.start(); 066 semiautomaticThread.moved(); 067 } 068 } 069 070 /** 071 * Resets the semiautomatic mode thread. 072 */ 073 public static void resetThread() { 074 semiautomaticThread.interrupt(); 075 semiautomaticThread = new SemiautomaticThread(); 076 } 077 078 private static class SemiautomaticThread extends Thread { 079 080 /** If in semiautomatic mode, the last Epoch time when there was a download */ 081 private long lastDownload; 082 083 private boolean moved; 084 085 @Override 086 public void run() { 087 while (true) { 088 if (this.moved && Calendar.getInstance().getTimeInMillis() - this.lastDownload >= DOWNLOAD_COOLDOWN) { 089 this.lastDownload = Calendar.getInstance().getTimeInMillis(); 090 StreetsideDownloader.downloadVisibleArea(); 091 this.moved = false; 092 StreetsideLayer.invalidateInstance(); 093 } 094 try { 095 Thread.sleep(100); 096 } catch (InterruptedException e) { 097 return; 098 } 099 } 100 } 101 102 public void moved() { 103 this.moved = true; 104 } 105 } 106}