Changeset 29744 in osm for applications/editors/josm/plugins/download_along/src
- Timestamp:
- 2013-07-06T15:06:23+02:00 (12 years ago)
- Location:
- applications/editors/josm/plugins/download_along/src/org/openstreetmap/josm/plugin/download_along
- Files:
-
- 2 added
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
applications/editors/josm/plugins/download_along/src/org/openstreetmap/josm/plugin/download_along/DownloadAlong.java
r29729 r29744 1 1 package org.openstreetmap.josm.plugin.download_along; 2 2 3 import java.awt.GridBagLayout;4 import java.awt.event.ActionEvent;5 import java.awt.event.KeyEvent;6 import java.awt.geom.Area;7 import java.awt.geom.Rectangle2D;8 import java.util.Collection;9 import java.util.ArrayList;10 import java.util.List;11 import java.util.concurrent.Future;12 13 import javax.swing.JLabel;14 import javax.swing.JList;15 import javax.swing.JMenuItem;16 import javax.swing.JOptionPane;17 import javax.swing.JPanel;18 19 import static org.openstreetmap.josm.tools.I18n.tr;20 21 3 import org.openstreetmap.josm.Main; 22 import org.openstreetmap.josm.actions.JosmAction;23 import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTaskList;24 import org.openstreetmap.josm.data.coor.LatLon;25 import org.openstreetmap.josm.data.osm.Node;26 import org.openstreetmap.josm.data.osm.OsmPrimitive;27 import org.openstreetmap.josm.data.osm.Way;28 4 import org.openstreetmap.josm.gui.MainMenu; 29 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;30 5 import org.openstreetmap.josm.plugins.Plugin; 31 6 import org.openstreetmap.josm.plugins.PluginInformation; 32 import org.openstreetmap.josm.tools.GBC;33 import org.openstreetmap.josm.tools.Shortcut;34 7 35 8 public class DownloadAlong extends Plugin { 36 privatestatic final String PREF_DOWNLOAD_ALONG_TRACK_DISTANCE = "downloadAlong.downloadAlongTrack.distance";37 privatestatic final String PREF_DOWNLOAD_ALONG_TRACK_AREA = "downloadAlong.downloadAlongTrack.area";9 static final String PREF_DOWNLOAD_ALONG_TRACK_DISTANCE = "downloadAlong.downloadAlongTrack.distance"; 10 static final String PREF_DOWNLOAD_ALONG_TRACK_AREA = "downloadAlong.downloadAlongTrack.area"; 38 11 39 JMenuItem DownloadAlong; 40 41 public DownloadAlong(PluginInformation info) { 42 super(info); 43 DownloadAlong = MainMenu.add(Main.main.menu.toolsMenu, 44 new DownloadAlongAction()); 45 46 } 47 48 private static class DownloadAlongAction extends JosmAction { 49 /** 50 * 51 */ 52 private static final long serialVersionUID = 1L; 53 54 public DownloadAlongAction() { 55 super(tr("Download along..."), "download_along", 56 tr("Download OSM data along the selected ways."), 57 Shortcut.registerShortcut("tools:download_along", tr("Tool: {0}", 58 tr("Download Along")), KeyEvent.VK_D, Shortcut.ALT_SHIFT), true); 59 } 60 61 public void actionPerformed(ActionEvent e) { 62 Collection<OsmPrimitive> selection = Main.main.getCurrentDataSet() 63 .getSelected(); 64 65 int ways = 0; 66 for (OsmPrimitive prim : selection) { 67 if (prim instanceof Way) 68 ways++; 69 } 70 71 if (ways < 1) { 72 JOptionPane.showMessageDialog(Main.parent, 73 tr("Please select 1 or more ways to download along")); 74 return; 75 } 76 77 JPanel msg = new JPanel(new GridBagLayout()); 78 Integer dist[] = { 5000, 500, 50 }; 79 Integer area[] = { 20, 10, 5, 1 }; 80 81 msg.add(new JLabel(tr("Download everything within:")), GBC.eol()); 82 String s[] = new String[dist.length]; 83 for (int i = 0; i < dist.length; ++i) { 84 s[i] = tr("{0} meters", dist[i]); 85 } 86 JList buffer = new JList(s); 87 buffer.setSelectedIndex(Main.pref.getInteger( 88 PREF_DOWNLOAD_ALONG_TRACK_DISTANCE, 0)); 89 msg.add(buffer, GBC.eol()); 90 91 msg.add(new JLabel(tr("Maximum area per request:")), GBC.eol()); 92 s = new String[area.length]; 93 for (int i = 0; i < area.length; ++i) { 94 s[i] = tr("{0} sq km", area[i]); 95 } 96 JList maxRect = new JList(s); 97 maxRect.setSelectedIndex(Main.pref.getInteger( 98 PREF_DOWNLOAD_ALONG_TRACK_AREA, 0)); 99 msg.add(maxRect, GBC.eol()); 100 101 int ret = JOptionPane.showConfirmDialog(Main.parent, msg, 102 tr("Download from OSM along this track"), 103 JOptionPane.OK_CANCEL_OPTION, JOptionPane.QUESTION_MESSAGE); 104 switch (ret) { 105 case JOptionPane.CANCEL_OPTION: 106 case JOptionPane.CLOSED_OPTION: 107 return; 108 default: 109 // continue 110 } 111 112 Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_DISTANCE, buffer 113 .getSelectedIndex()); 114 Main.pref.putInteger(PREF_DOWNLOAD_ALONG_TRACK_AREA, maxRect 115 .getSelectedIndex()); 116 117 /* 118 * Find the average latitude for the data we're contemplating, so we can 119 * know how many metres per degree of longitude we have. 120 */ 121 double latsum = 0; 122 int latcnt = 0; 123 124 for (OsmPrimitive prim : selection) { 125 if (prim instanceof Way) { 126 Way way = (Way) prim; 127 for (Node n : way.getNodes()) { 128 latsum += n.getCoor().lat(); 129 latcnt++; 130 } 131 } 132 } 133 134 double avglat = latsum / latcnt; 135 double scale = Math.cos(Math.toRadians(avglat)); 136 137 /* 138 * Compute buffer zone extents and maximum bounding box size. Note that 139 * the maximum we ever offer is a bbox area of 0.002, while the API 140 * theoretically supports 0.25, but as soon as you touch any built-up 141 * area, that kind of bounding box will download forever and then stop 142 * because it has more than 50k nodes. 143 */ 144 Integer i = buffer.getSelectedIndex(); 145 int buffer_dist = dist[i < 0 ? 0 : i]; 146 double buffer_y = buffer_dist / 100000.0; 147 double buffer_x = buffer_y / scale; 148 i = maxRect.getSelectedIndex(); 149 double max_area = area[i < 0 ? 0 : i] / 10000.0 / scale; 150 Area a = new Area(); 151 Rectangle2D r = new Rectangle2D.Double(); 152 153 /* 154 * Collect the combined area of all gpx points plus buffer zones around 155 * them. We ignore points that lie closer to the previous point than the 156 * given buffer size because otherwise this operation takes ages. 157 */ 158 LatLon previous = null; 159 for (OsmPrimitive prim : selection) { 160 Way way = (Way) prim; 161 for (Node p : way.getNodes()) { 162 LatLon c = p.getCoor(); 163 ArrayList<LatLon> intermediateNodes = new ArrayList<LatLon>(); 164 if (previous != null 165 && c.greatCircleDistance(previous) > buffer_dist) { 166 Double d = c.greatCircleDistance(previous) / buffer_dist; 167 int nbNodes = d.intValue(); 168 System.out.println(tr("{0} intermediate nodes to download.", nbNodes)); 169 System.out.println(tr("between {0} {1} and {2} {3}", c.lat(), c.lon(), previous.lat(), previous.lon())); 170 for (i = 1; i < nbNodes; i++) { 171 intermediateNodes.add(new LatLon(previous.lat()+(i * (c.lat() - previous.lat()) 172 / (nbNodes+1)), previous.lon()+(i * (c.lon() - previous.lon()) / (nbNodes+1)))); 173 System.out.println(tr(" adding {0} {1}", previous.lat()+(i * (c.lat() - previous.lat()) 174 / (nbNodes+1)), previous.lon()+(i * (c.lon() - previous.lon()) / (nbNodes+1)))); 175 } 176 } 177 intermediateNodes.add(c); 178 for (LatLon d : intermediateNodes) { 179 if (previous == null 180 || d.greatCircleDistance(previous) > buffer_dist) { 181 // we add a buffer around the point. 182 r.setRect(d.lon() - buffer_x, d.lat() - buffer_y, 2 * buffer_x, 183 2 * buffer_y); 184 a.add(new Area(r)); 185 previous = d; 186 } 187 } 188 previous = c; 189 } 190 } 191 192 /* 193 * Area "a" now contains the hull that we would like to download data for. 194 * however we can only download rectangles, so the following is an attempt 195 * at finding a number of rectangles to download. 196 * 197 * The idea is simply: Start out with the full bounding box. If it is too 198 * large, then split it in half and repeat recursively for each half until 199 * you arrive at something small enough to download. The algorithm is 200 * improved by always using the intersection between the rectangle and the 201 * actual desired area. For example, if you have a track that goes like 202 * this: +----+ | /| | / | | / | |/ | +----+ then we would first look at 203 * downloading the whole rectangle (assume it's too big), after that we 204 * split it in half (upper and lower half), but we donot request the full 205 * upper and lower rectangle, only the part of the upper/lower rectangle 206 * that actually has something in it. 207 */ 208 209 List<Rectangle2D> toDownload = new ArrayList<Rectangle2D>(); 210 211 addToDownload(a, a.getBounds(), toDownload, max_area); 212 213 msg = new JPanel(new GridBagLayout()); 214 215 msg.add(new JLabel(tr("<html>This action will require {0} individual<br>" 216 + "download requests. Do you wish<br>to continue?</html>", toDownload 217 .size())), GBC.eol()); 218 219 if (toDownload.size() > 1) { 220 ret = JOptionPane.showConfirmDialog(Main.parent, msg, 221 tr("Download from OSM along this track"), 222 JOptionPane.OK_CANCEL_OPTION, JOptionPane.PLAIN_MESSAGE); 223 switch (ret) { 224 case JOptionPane.CANCEL_OPTION: 225 case JOptionPane.CLOSED_OPTION: 226 return; 227 default: 228 // continue 229 } 230 } 231 final PleaseWaitProgressMonitor monitor = new PleaseWaitProgressMonitor( 232 tr("Download data")); 233 final Future<?> future = new DownloadOsmTaskList().download(false, 234 toDownload, monitor); 235 Main.worker.submit(new Runnable() { 236 public void run() { 237 try { 238 future.get(); 239 } catch (Exception e) { 240 e.printStackTrace(); 241 return; 242 } 243 monitor.close(); 244 } 245 }); 246 } 247 248 private static void addToDownload(Area a, Rectangle2D r, 249 Collection<Rectangle2D> results, double max_area) { 250 Area tmp = new Area(r); 251 // intersect with sought-after area 252 tmp.intersect(a); 253 if (tmp.isEmpty()) 254 return; 255 Rectangle2D bounds = tmp.getBounds2D(); 256 if (bounds.getWidth() * bounds.getHeight() > max_area) { 257 // the rectangle gets too large; split it and make recursive call. 258 Rectangle2D r1; 259 Rectangle2D r2; 260 if (bounds.getWidth() > bounds.getHeight()) { 261 // rectangles that are wider than high are split into a left and right 262 // half, 263 r1 = new Rectangle2D.Double(bounds.getX(), bounds.getY(), bounds 264 .getWidth() / 2, bounds.getHeight()); 265 r2 = new Rectangle2D.Double(bounds.getX() + bounds.getWidth() / 2, 266 bounds.getY(), bounds.getWidth() / 2, bounds.getHeight()); 267 } else { 268 // others into a top and bottom half. 269 r1 = new Rectangle2D.Double(bounds.getX(), bounds.getY(), bounds 270 .getWidth(), bounds.getHeight() / 2); 271 r2 = new Rectangle2D.Double(bounds.getX(), bounds.getY() 272 + bounds.getHeight() / 2, bounds.getWidth(), 273 bounds.getHeight() / 2); 274 } 275 addToDownload(a, r1, results, max_area); 276 addToDownload(a, r2, results, max_area); 277 } else { 278 results.add(bounds); 279 } 280 } 281 282 @Override 283 protected void updateEnabledState() { 284 setEnabled(getEditLayer() != null); 285 } 286 287 @Override 288 protected void updateEnabledState( 289 Collection<? extends OsmPrimitive> selection) { 290 // do nothing 291 } 292 } 12 public DownloadAlong(PluginInformation info) { 13 super(info); 14 MainMenu.add(Main.main.menu.toolsMenu, new DownloadAlongAction()); 15 } 293 16 }
Note:
See TracChangeset
for help on using the changeset viewer.