source: osm/applications/editors/josm/plugins/waydownloader/src/WayDownloaderPlugin.java@ 15412

Last change on this file since 15412 was 15412, checked in by harrywood, 17 years ago

new WayDownloader JOSM plugin

File size: 8.7 KB
Line 
1import static org.openstreetmap.josm.tools.I18n.tr;
2
3import java.awt.event.ActionEvent;
4import java.awt.event.KeyEvent;
5import java.util.ArrayList;
6import java.util.Collection;
7import java.util.Iterator;
8import java.util.LinkedList;
9
10import javax.swing.JOptionPane;
11
12import org.openstreetmap.josm.Main;
13import org.openstreetmap.josm.actions.JosmAction;
14import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
15import org.openstreetmap.josm.actions.MergeNodesAction;
16import org.openstreetmap.josm.data.Bounds;
17import org.openstreetmap.josm.data.osm.DataSource;
18import org.openstreetmap.josm.data.osm.Node;
19import org.openstreetmap.josm.data.osm.OsmPrimitive;
20import org.openstreetmap.josm.data.osm.Way;
21import org.openstreetmap.josm.gui.MainMenu;
22import org.openstreetmap.josm.plugins.Plugin;
23import org.openstreetmap.josm.tools.Shortcut;
24
25/**
26 * Plugin class for the Way Downloader plugin
27 *
28 * @author Harry Wood
29 */
30public class WayDownloaderPlugin extends Plugin {
31
32 private Way priorConnectedWay = null;
33 private Node selectedNode = null;
34
35
36 /** Plugin constructor called at JOSM startup */
37 public WayDownloaderPlugin() {
38 //add WayDownloadAction to tools menu
39 MainMenu.add(Main.main.menu.toolsMenu, new WayDownloadAction());
40 }
41
42 private class WayDownloadAction extends JosmAction implements Runnable {
43
44 /** Set up the action (text appearing on the menu, keyboard shortcut etc */
45 public WayDownloadAction() {
46
47 super( "Way Download" ,
48 "way-download",
49 "Download map data on the end of selected way",
50 Shortcut.registerShortcut("waydownloader:waydownload", "Way Download", KeyEvent.VK_W, Shortcut.GROUP_MENU, Shortcut.SHIFT_DEFAULT),
51 true);
52 }
53
54 /** Called when the WayDownloadAction action is triggered (e.g. user clicked the menu option) */
55 public void actionPerformed(ActionEvent e) {
56
57 System.out.println("Way Download");
58
59 String errMsg = null;
60
61 selectedNode = null;
62 Collection<OsmPrimitive> selection = Main.ds.getSelectedNodes();
63
64 if (selection.size()==0) {
65 selection = Main.ds.getSelectedWays();
66 if (!workFromWaySelection(selection)) {
67 errMsg = tr("Select a starting node on the end of a way");
68 }
69 selection = Main.ds.getSelectedNodes();
70 }
71
72 if ( selection.size()==0 || selection.size()>1 ) {
73 errMsg = tr("Select a starting node on the end of a way");
74 } else {
75 OsmPrimitive p = selection.iterator().next();
76
77
78
79 if (!(p instanceof Node)) {
80 errMsg = tr("Select a starting node on the end of a way");
81 } else {
82 selectedNode = (Node) p;
83
84
85 Main.map.mapView.zoomTo(selectedNode.eastNorth , Main.map.mapView.getScale());
86
87 //Before downloading. Figure a few things out.
88 //Find connected way
89 ArrayList<Way> connectedWays = findConnectedWays();
90
91 if (connectedWays.size()==0) {
92 errMsg = tr("Select a starting node on the end of a way");
93 } else {
94 priorConnectedWay =(Way) connectedWays.get(0);
95
96 //Download a little rectangle around the selected node
97 double latbuffer=0.0003; //TODO make this an option
98 double lonbuffer=0.0005;
99 DownloadOsmTask downloadTask = new DownloadOsmTask();
100 downloadTask.download( null,
101 selectedNode.coor.lat()-latbuffer,
102 selectedNode.coor.lon()-lonbuffer,
103 selectedNode.coor.lat()+latbuffer,
104 selectedNode.coor.lon()+lonbuffer);
105
106 //The download is scheduled to be executed.
107 //Now schedule the run() method (below) to be executed once that's completed.
108 Main.worker.execute(this);
109
110 }
111 }
112 }
113
114 if(errMsg != null)
115 JOptionPane.showMessageDialog(Main.parent, errMsg);
116
117
118 }
119
120 /**
121 * Logic to excute after the download has happened
122 */
123 public void run() {
124 //Find ways connected to the node after the download
125 ArrayList<Way> connectedWays = findConnectedWays();
126
127 String errMsg = null;
128 if (connectedWays.size()==0) {
129 throw new RuntimeException("Way downloader data inconsistency. priorConnectedWay (" +
130 priorConnectedWay.toString() + ") wasn't discovered after download");
131
132 } else if (connectedWays.size()==1) {
133 //Just one way connecting the node still. Presumably the one which was there before
134
135 //Check if it's just a duplicate node
136 Node dupeNode = duplicateNode();
137 if (dupeNode!=null) {
138
139 if (JOptionPane.showConfirmDialog(null, "Merge duplicate node?")==JOptionPane.YES_OPTION) {
140 LinkedList<Node> dupeNodes = new LinkedList<Node>();
141 dupeNodes.add(dupeNode);
142 MergeNodesAction.mergeNodes(dupeNodes, selectedNode);
143
144 connectedWays = findConnectedWays(); //Carry on
145 }
146
147
148 } else {
149 errMsg = tr("Reached the end of the line");
150 }
151
152 }
153
154 if (connectedWays.size()>2) {
155 //Three or more ways meeting at this node. Means we have a junction.
156 errMsg = tr("Reached a junction");
157
158 } else if (connectedWays.size()==2) {
159 //Two connected ways (The "normal" way downloading case)
160 //Figure out which of the two is new.
161 System.out.println("connectedWays.toString()=" + connectedWays.toString());
162 Way wayA = (Way) connectedWays.get(0);
163 Way wayB = (Way) connectedWays.get(1);
164 Way nextWay = wayA;
165 if (priorConnectedWay.equals(wayA)) nextWay = wayB;
166
167 Node nextNode = findOtherEnd(nextWay, selectedNode);
168
169 //Select the next node
170 Main.ds.setSelected(nextNode);
171
172 Main.map.mapView.zoomTo(nextNode.eastNorth , Main.map.mapView.getScale());
173
174 }
175 if(errMsg != null)
176 JOptionPane.showMessageDialog(Main.parent, errMsg);
177 }
178 }
179
180 /** See if there's another node at the same coordinates. If so return it. Otherwise null */
181 private Node duplicateNode() {
182 Iterator nodesIter = Main.ds.nodes.iterator();
183 while (nodesIter.hasNext()) {
184 Node onNode = (Node) nodesIter.next();
185 if (!onNode.equals(this.selectedNode)
186 && onNode.coor.lat()==selectedNode.coor.lat()
187 && onNode.coor.lon()==selectedNode.coor.lon()) {
188 return onNode;
189 }
190 }
191 return null;
192 }
193
194 /** Given the the node on one end of the way, return the node on the other end */
195 private Node findOtherEnd(Way way, Node firstEnd) {
196 Node otherEnd = way.nodes.get(0);
197 if (otherEnd.equals(firstEnd)) otherEnd = way.nodes.get(way.nodes.size()-1);
198 return otherEnd;
199 }
200
201 /** find set of ways which have an end on the selectedNode */
202 private ArrayList<Way> findConnectedWays() {
203 ArrayList<Way> connectedWays = new ArrayList<Way>();
204
205 //loop through every way
206 Iterator waysIter = Main.ds.ways.iterator();
207 while (waysIter.hasNext()) {
208 Way onWay = (Way) waysIter.next();
209
210
211 Object[] nodes = onWay.nodes.toArray();
212 if (nodes.length<2) {
213 //Should never happen should it? TODO: investigate. For the moment ignore these
214 System.err.println("WayDownloader plugin encountered a way with " + nodes.length + " nodes :" + onWay.toString());
215 } else {
216 Node firstNode = (Node) nodes[0];
217 Node lastNode = (Node) nodes[nodes.length-1];
218
219 if (firstNode.equals(selectedNode) || lastNode.equals(selectedNode)) {
220 //Found it
221 connectedWays.add(onWay);
222 }
223 }
224 }
225 return connectedWays;
226 }
227
228 /**
229 * given a selected way, select a node on the end of the way which is not in a downloaded area
230 * return true if this worked
231 */
232 private boolean workFromWaySelection(Collection<OsmPrimitive> selection) {
233
234 if (selection.size()>1) {
235 //more than one way selected
236 return false;
237 } else {
238 Way selectedWay = (Way) selection.toArray()[0];
239 selectedNode = (Node) selectedWay.nodes.get(0);
240
241 if (isDownloaded(selectedNode)) {
242 selectedNode = findOtherEnd(selectedWay, selectedNode);
243
244 if (isDownloaded(selectedNode)) return false;
245 }
246 }
247 Main.ds.setSelected(selectedNode);
248 return true;
249 }
250
251 private boolean isDownloaded(Node node) {
252 Iterator downloadedAreasIter = Main.ds.dataSources.iterator();
253 while (downloadedAreasIter.hasNext()) {
254 DataSource datasource = (DataSource) downloadedAreasIter.next();
255 Bounds bounds = datasource.bounds;
256
257 if (node.coor.lat()>bounds.min.lat() &&
258 node.coor.lat()<bounds.max.lat() &&
259 node.coor.lon()>bounds.min.lon() &&
260 node.coor.lon()<bounds.max.lon()) {
261 return true;
262 }
263 }
264 return false;
265 }
266}
Note: See TracBrowser for help on using the repository browser.