Ignore:
Timestamp:
2013-07-06T15:06:23+02:00 (12 years ago)
Author:
donvip
Message:

[josm_download_along] code cleanup/refactoring in order to fix plugin tickets

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  
    11package org.openstreetmap.josm.plugin.download_along;
    22
    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 
    213import 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;
    284import org.openstreetmap.josm.gui.MainMenu;
    29 import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
    305import org.openstreetmap.josm.plugins.Plugin;
    316import org.openstreetmap.josm.plugins.PluginInformation;
    32 import org.openstreetmap.josm.tools.GBC;
    33 import org.openstreetmap.josm.tools.Shortcut;
    347
    358public class DownloadAlong extends Plugin {
    36   private static final String PREF_DOWNLOAD_ALONG_TRACK_DISTANCE = "downloadAlong.downloadAlongTrack.distance";
    37   private static 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";
    3811
    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        }
    29316}
Note: See TracChangeset for help on using the changeset viewer.