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

Last change on this file since 16963 was 16963, checked in by stoecker, 16 years ago

fixed josm 2965 - patch by dmuecke - Array Bounds

File size: 9.3 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.LinkedList;
8
9import javax.swing.JOptionPane;
10
11import org.openstreetmap.josm.Main;
12import org.openstreetmap.josm.actions.JosmAction;
13import org.openstreetmap.josm.actions.MergeNodesAction;
14import org.openstreetmap.josm.actions.downloadtasks.DownloadOsmTask;
15import org.openstreetmap.josm.data.Bounds;
16import org.openstreetmap.josm.data.osm.DataSource;
17import org.openstreetmap.josm.data.osm.Node;
18import org.openstreetmap.josm.data.osm.OsmPrimitive;
19import org.openstreetmap.josm.data.osm.Way;
20import org.openstreetmap.josm.gui.MainMenu;
21import org.openstreetmap.josm.gui.progress.PleaseWaitProgressMonitor;
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.main.getCurrentDataSet().getSelectedNodes();
63
64 if (selection.size()==0) {
65 selection = Main.main.getCurrentDataSet().getSelectedWays();
66 if (!workFromWaySelection(selection)) {
67 errMsg = tr("Select a starting node on the end of a way");
68 }
69 selection = Main.main.getCurrentDataSet().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.getEastNorth());
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 =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.getCoor().lat()-latbuffer,
102 selectedNode.getCoor().lon()-lonbuffer,
103 selectedNode.getCoor().lat()+latbuffer,
104 selectedNode.getCoor().lon()+lonbuffer,
105 new PleaseWaitProgressMonitor());
106
107 //The download is scheduled to be executed.
108 //Now schedule the run() method (below) to be executed once that's completed.
109 Main.worker.execute(this);
110 }
111 }
112 }
113
114 if(errMsg != null)
115 JOptionPane.showMessageDialog(Main.parent, errMsg);
116 }
117
118 /**
119 * Logic to excute after the download has happened
120 */
121 public void run() {
122 //Find ways connected to the node after the download
123 ArrayList<Way> connectedWays = findConnectedWays();
124
125 String errMsg = null;
126 if (connectedWays.size()==0) {
127 throw new RuntimeException("Way downloader data inconsistency. priorConnectedWay (" +
128 priorConnectedWay.toString() + ") wasn't discovered after download");
129
130 } else if (connectedWays.size()==1) {
131 //Just one way connecting the node still. Presumably the one which was there before
132
133 //Check if it's just a duplicate node
134 Node dupeNode = duplicateNode();
135 if (dupeNode!=null) {
136
137 if (JOptionPane.showConfirmDialog(null, "Merge duplicate node?")==JOptionPane.YES_OPTION) {
138 LinkedList<Node> dupeNodes = new LinkedList<Node>();
139 dupeNodes.add(dupeNode);
140 new MergeNodesAction().mergeNodes(dupeNodes, selectedNode);
141
142 connectedWays = findConnectedWays(); //Carry on
143 }
144
145
146 } else {
147 errMsg = tr("Reached the end of the line");
148 }
149
150 }
151
152 if (connectedWays.size()>2) {
153 //Three or more ways meeting at this node. Means we have a junction.
154 errMsg = tr("Reached a junction");
155
156 } else if (connectedWays.size()==2) {
157 //Two connected ways (The "normal" way downloading case)
158 //Figure out which of the two is new.
159 System.out.println("connectedWays.toString()=" + connectedWays.toString());
160 Way wayA = connectedWays.get(0);
161 Way wayB = connectedWays.get(1);
162 Way nextWay = wayA;
163 if (priorConnectedWay.equals(wayA)) nextWay = wayB;
164
165 Node nextNode = findOtherEnd(nextWay, selectedNode);
166
167 //Select the next node
168 Main.main.getCurrentDataSet().setSelected(nextNode);
169
170 Main.map.mapView.zoomTo(nextNode.getEastNorth());
171 }
172 if(errMsg != null)
173 JOptionPane.showMessageDialog(Main.parent, errMsg);
174 }
175 }
176
177 /** See if there's another node at the same coordinates. If so return it. Otherwise null */
178 private Node duplicateNode() {
179 for (Node onNode:Main.main.getCurrentDataSet().nodes) {
180 if (!onNode.equals(this.selectedNode)
181 && !onNode.incomplete
182 && onNode.getCoor().lat()==selectedNode.getCoor().lat()
183 && onNode.getCoor().lon()==selectedNode.getCoor().lon()) {
184 return onNode;
185 }
186 }
187 return null;
188 }
189
190 /** Given the the node on one end of the way, return the node on the other end */
191 private Node findOtherEnd(Way way, Node firstEnd) {
192 Node otherEnd = way.firstNode();
193 if (otherEnd.equals(firstEnd)) otherEnd = way.lastNode();
194 return otherEnd;
195 }
196
197 /** find set of ways which have an end on the selectedNode */
198 private ArrayList<Way> findConnectedWays() {
199 ArrayList<Way> connectedWays = new ArrayList<Way>();
200
201 //loop through every way
202 for (Way onWay:Main.main.getCurrentDataSet().ways) {
203 if (onWay.getNodesCount() >= 2) {
204 if (onWay.isFirstLastNode(selectedNode)) {
205 //Found it
206 connectedWays.add(onWay);
207 }
208 }
209 }
210 return connectedWays;
211 }
212
213 /**
214 * given a selected way, select a node on the end of the way which is not in a downloaded area
215 * return true if this worked
216 */
217 private boolean workFromWaySelection(Collection<OsmPrimitive> selection) {
218
219 if (selection.size() != 1)
220 return false;
221 Way selectedWay = (Way) selection.iterator().next();
222 selectedNode = selectedWay.firstNode();
223
224 if (isDownloaded(selectedNode)) {
225 selectedNode = selectedWay.lastNode();
226
227 if (isDownloaded(selectedNode)) return false;
228 }
229 Main.main.getCurrentDataSet().setSelected(selectedNode);
230 return true;
231 }
232
233 private boolean isDownloaded(Node node) {
234 for (DataSource datasource:Main.main.getCurrentDataSet().dataSources) {
235 Bounds bounds = datasource.bounds;
236
237 if (node.getCoor().lat()>bounds.min.lat() &&
238 node.getCoor().lat()<bounds.max.lat() &&
239 node.getCoor().lon()>bounds.min.lon() &&
240 node.getCoor().lon()<bounds.max.lon()) {
241 return true;
242 }
243 }
244 return false;
245 }
246}
Note: See TracBrowser for help on using the repository browser.