source: osm/applications/editors/josm/plugins/cadastre-fr/src/cadastre_fr/DownloadSVGBuilding.java@ 15707

Last change on this file since 15707 was 13784, checked in by pieren, 16 years ago

Fix minor bugs, add the fixed size grab scale configurable, fix pbls in transparency.

File size: 10.7 KB
Line 
1package cadastre_fr;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.io.BufferedOutputStream;
6import java.io.BufferedReader;
7import java.io.File;
8import java.io.FileOutputStream;
9import java.io.IOException;
10import java.io.InputStream;
11import java.io.InputStreamReader;
12import java.net.HttpURLConnection;
13import java.net.MalformedURLException;
14import java.net.URL;
15import java.util.ArrayList;
16import java.util.Collection;
17import java.util.LinkedList;
18
19import javax.swing.JOptionPane;
20
21import org.openstreetmap.josm.Main;
22import org.openstreetmap.josm.command.AddCommand;
23import org.openstreetmap.josm.command.Command;
24import org.openstreetmap.josm.command.SequenceCommand;
25import org.openstreetmap.josm.data.coor.EastNorth;
26import org.openstreetmap.josm.data.osm.DataSet;
27import org.openstreetmap.josm.data.osm.Node;
28import org.openstreetmap.josm.data.osm.Way;
29import org.openstreetmap.josm.gui.MapView;
30import org.openstreetmap.josm.gui.PleaseWaitRunnable;
31import org.openstreetmap.josm.io.ProgressInputStream;
32
33public class DownloadSVGBuilding extends PleaseWaitRunnable {
34
35 private WMSLayer wmsLayer;
36 private CadastreGrabber grabber = CadastrePlugin.cadastreGrabber;
37 private CadastreInterface wmsInterface;
38 private String svg = null;
39 private static EastNorthBound currentView = null;
40 private EastNorthBound viewBox = null;
41
42 public DownloadSVGBuilding(WMSLayer wmsLayer) {
43 super(tr("Downloading {0}", wmsLayer.name));
44
45 this.wmsLayer = wmsLayer;
46 this.wmsInterface = grabber.getWmsInterface();
47 }
48
49 @Override
50 public void realRun() throws IOException {
51 Main.pleaseWaitDlg.currentAction.setText(tr("Contacting WMS Server..."));
52 try {
53 if (wmsInterface.retrieveInterface(wmsLayer)) {
54 svg = grabBoundary(currentView);
55 if (svg == null)
56 return;
57 getViewBox(svg);
58 if (viewBox == null)
59 return;
60 createBuildings(svg);
61 }
62 } catch (DuplicateLayerException e) {
63 System.err.println("removed a duplicated layer");
64 }
65 }
66
67 @Override
68 protected void cancel() {
69 grabber.getWmsInterface().cancel();
70 }
71
72 @Override
73 protected void finish() {
74 }
75
76 private boolean getViewBox(String svg) {
77 double[] box = new SVGParser().getViewBox(svg);
78 if (box != null) {
79 viewBox = new EastNorthBound(new EastNorth(box[0], box[1]),
80 new EastNorth(box[0]+box[2], box[1]+box[3]));
81 return true;
82 }
83 System.out.println("Unable to parse SVG data (viewBox)");
84 return false;
85 }
86
87 /**
88 * The svg contains more than one commune boundary defined by path elements. So detect
89 * which path element is the best fitting to the viewBox and convert it to OSM objects
90 */
91 private void createBuildings(String svg) {
92 String[] SVGpaths = new SVGParser().getClosedPaths(svg);
93 ArrayList<ArrayList<EastNorth>> eastNorths = new ArrayList<ArrayList<EastNorth>>();
94
95 // convert SVG nodes to eastNorth coordinates
96 for (int i=0; i< SVGpaths.length; i++) {
97 ArrayList<EastNorth> eastNorth = new ArrayList<EastNorth>();
98 createNodes(SVGpaths[i], eastNorth);
99 if (eastNorth.size() > 2)
100 eastNorths.add(eastNorth);
101 }
102
103 // create nodes and closed ways
104 DataSet svgDataSet = new DataSet();
105 for (ArrayList<EastNorth> path : eastNorths) {
106 Way wayToAdd = new Way();
107 for (EastNorth eastNorth : path) {
108 Node nodeToAdd = new Node(Main.proj.eastNorth2latlon(eastNorth));
109 // check if new node is not already created by another new path
110 Node nearestNewNode = checkNearestNode(nodeToAdd, svgDataSet.nodes);
111 if (nearestNewNode == nodeToAdd)
112 svgDataSet.addPrimitive(nearestNewNode);
113 wayToAdd.nodes.add(nearestNewNode); // either a new node or an existing one
114 }
115 wayToAdd.nodes.add(wayToAdd.nodes.get(0)); // close the way
116 svgDataSet.addPrimitive(wayToAdd);
117 }
118
119 // TODO remove small boxes (4 nodes with less than 1 meter distance)
120 /*
121 for (Way w : svgDataSet.ways)
122 if (w.nodes.size() == 5)
123 for (int i = 0; i < w.nodes.size()-2; i++) {
124 if (w.nodes.get(i).eastNorth.distance(w.nodes.get(i+1).eastNorth))
125 }*/
126
127 // simplify ways and check if we can reuse existing OSM nodes
128 for (Way wayToAdd : svgDataSet.ways)
129 new SimplifyWay().simplifyWay(wayToAdd, svgDataSet, 0.5);
130 // check if the new way or its nodes is already in OSM layer
131 for (Node n : svgDataSet.nodes) {
132 Node nearestNewNode = checkNearestNode(n, Main.ds.nodes);
133 if (nearestNewNode != n) {
134 // replace the SVG node by the OSM node
135 for (Way w : svgDataSet.ways) {
136 int replaced = 0;
137 for (Node node : w.nodes)
138 if (node == n) {
139 node = nearestNewNode;
140 replaced++;
141 }
142 if (w.nodes.size() == replaced)
143 w.delete(true);
144 }
145 n.delete(true);
146 }
147
148 }
149
150 Collection<Command> cmds = new LinkedList<Command>();
151 for (Node node : svgDataSet.nodes)
152 if (!node.deleted)
153 cmds.add(new AddCommand(node));
154 for (Way way : svgDataSet.ways)
155 if (!way.deleted)
156 cmds.add(new AddCommand(way));
157 Main.main.undoRedo.add(new SequenceCommand(tr("Create buildings"), cmds));
158 Main.map.repaint();
159 }
160
161 private void createNodes(String SVGpath, ArrayList<EastNorth> eastNorth) {
162 // looks like "M981283.38 368690.15l143.81 72.46 155.86 ..."
163 String[] coor = SVGpath.split("[MlZ ]"); //coor[1] is x, coor[2] is y
164 double dx = Double.parseDouble(coor[1]);
165 double dy = Double.parseDouble(coor[2]);
166 for (int i=3; i<coor.length; i+=2){
167 if (coor[i].equals("")) {
168 eastNorth.clear(); // some paths are just artifacts
169 return;
170 }
171 double east = dx+=Double.parseDouble(coor[i]);
172 double north = dy+=Double.parseDouble(coor[i+1]);
173 eastNorth.add(new EastNorth(east,north));
174 }
175 // flip the image (svg using a reversed Y coordinate system)
176 double pivot = viewBox.min.getY() + (viewBox.max.getY() - viewBox.min.getY()) / 2;
177 for (EastNorth en : eastNorth) {
178 en.setLocation(en.east(), 2 * pivot - en.north());
179 }
180 return;
181 }
182
183 /**
184 * Check if node can be reused.
185 * @param nodeToAdd the candidate as new node
186 * @return the already existing node (if any), otherwise the new node candidate.
187 */
188 private Node checkNearestNode(Node nodeToAdd, Collection<Node> nodes) {
189 double epsilon = 0.05; // smallest distance considering duplicate node
190 for (Node n : nodes) {
191 if (!n.deleted && !n.incomplete) {
192 double dist = n.eastNorth.distance(nodeToAdd.eastNorth);
193 if (dist < epsilon) {
194 return n;
195 }
196 }
197 }
198 return nodeToAdd;
199 }
200
201 private String grabBoundary(EastNorthBound bbox) throws IOException {
202
203 try {
204 URL url = null;
205 url = getURLsvg(bbox);
206 System.out.println("grab:"+url);
207 return grabSVG(url);
208 } catch (MalformedURLException e) {
209 throw (IOException) new IOException(tr("CadastreGrabber: Illegal url.")).initCause(e);
210 }
211 }
212
213 private URL getURLsvg(EastNorthBound bbox) throws MalformedURLException {
214 String str = new String(wmsInterface.baseURL+"/scpc/wms?version=1.1&request=GetMap");
215 str += "&layers=";
216 str += "CDIF:LS2";
217 str += "&format=image/svg";
218 str += "&bbox="+bbox.min.east()+",";
219 str += bbox.min.north() + ",";
220 str += bbox.max.east() + ",";
221 str += bbox.max.north();
222 str += "&width=800&height=600"; // maximum allowed by wms server
223 str += "&exception=application/vnd.ogc.se_inimage";
224 str += "&styles=";
225 str += "LS2_90";
226 System.out.println("URL="+str);
227 return new URL(str.replace(" ", "%20"));
228 }
229
230 private String grabSVG(URL url) throws IOException {
231 wmsInterface.urlConn = (HttpURLConnection)url.openConnection();
232 wmsInterface.urlConn.setRequestMethod("GET");
233 wmsInterface.setCookie();
234 InputStream is = new ProgressInputStream(wmsInterface.urlConn, Main.pleaseWaitDlg);
235 File file = new File(CadastrePlugin.cacheDir + "building.svg");
236 String svg = new String();
237 try {
238 if (file.exists())
239 file.delete();
240 BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(file, true));
241 InputStreamReader isr =new InputStreamReader(is);
242 BufferedReader br = new BufferedReader(isr);
243 String line="";
244 while ( null!=(line=br.readLine())){
245 line += "\n";
246 bos.write(line.getBytes());
247 svg += line;
248 }
249 bos.close();
250 } catch (IOException e) {
251 e.printStackTrace(System.out);
252 }
253 is.close();
254 return svg;
255 }
256
257 public static void download(WMSLayer wmsLayer) {
258 MapView mv = Main.map.mapView;
259 currentView = new EastNorthBound(mv.getEastNorth(0, mv.getHeight()),
260 mv.getEastNorth(mv.getWidth(), 0));
261 if ((currentView.max.east() - currentView.min.east()) > 1000 ||
262 (currentView.max.north() - currentView.min.north() > 1000)) {
263 JOptionPane.showMessageDialog(Main.parent,
264 tr("To avoid cadastre WMS overload,\nbuilding import size is limited to 1 km2 max."));
265 return;
266 }
267 if (CadastrePlugin.autoSourcing == false) {
268 JOptionPane.showMessageDialog(Main.parent,
269 tr("Please, enable auto-sourcing and check cadastre millesime."));
270 return;
271 }
272 Main.worker.execute(new DownloadSVGBuilding(wmsLayer));
273 }
274
275}
Note: See TracBrowser for help on using the repository browser.