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

Last change on this file since 21202 was 20931, checked in by pieren, 16 years ago

add multi-cache management for buildings

File size: 29.1 KB
Line 
1package cadastre_fr;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.Color;
6import java.awt.Point;
7import java.awt.event.ActionEvent;
8import java.awt.event.KeyEvent;
9import java.awt.event.MouseEvent;
10import java.awt.event.MouseListener;
11import java.awt.event.MouseMotionListener;
12import java.util.ArrayList;
13import java.util.Collection;
14import java.util.Collections;
15import java.util.HashMap;
16import java.util.HashSet;
17import java.util.LinkedList;
18import java.util.List;
19import java.util.Map;
20import java.util.TreeMap;
21
22import javax.swing.JOptionPane;
23
24import org.openstreetmap.josm.Main;
25import org.openstreetmap.josm.gui.MapFrame;
26import org.openstreetmap.josm.actions.mapmode.MapMode;
27import org.openstreetmap.josm.command.AddCommand;
28import org.openstreetmap.josm.command.ChangeCommand;
29import org.openstreetmap.josm.command.ChangePropertyCommand;
30import org.openstreetmap.josm.command.Command;
31import org.openstreetmap.josm.command.MoveCommand;
32import org.openstreetmap.josm.command.SequenceCommand;
33import org.openstreetmap.josm.data.coor.EastNorth;
34import org.openstreetmap.josm.data.osm.BBox;
35import org.openstreetmap.josm.data.osm.DataSet;
36import org.openstreetmap.josm.data.osm.Node;
37import org.openstreetmap.josm.data.osm.Way;
38import org.openstreetmap.josm.data.osm.WaySegment;
39import org.openstreetmap.josm.tools.ImageProvider;
40import org.openstreetmap.josm.tools.Shortcut;
41import org.openstreetmap.josm.gui.layer.Layer;
42
43/**
44 * Trace a way around buildings from cadastre images.
45 * Inspired by Lakewalker plugin.
46 * @author Pieren
47 */
48public class Buildings extends MapMode implements MouseListener, MouseMotionListener {
49
50 private static final long serialVersionUID = 1L;
51 GeorefImage selectedImage;
52 WMSLayer selectedLayer;
53 private EastNorth clickedEastNorth;
54 private class Pixel {
55 public Point p;
56 public int dir;
57 @SuppressWarnings("unused")
58 public boolean toKeep;
59 public Pixel(int x, int y, int dir) {
60 this.p = new Point(x,y);
61 this.dir = dir;
62 }
63 @Override
64 public int hashCode() {
65 return p.hashCode();
66 }
67 @Override
68 public boolean equals(Object obj) {
69 if (obj instanceof Pixel)
70 return p.equals(new Point(((Pixel)obj).p.x, ((Pixel)obj).p.y));
71 return p.equals(obj);
72 }
73 @Override
74 public String toString() {
75 return new String("p="+p+", dir="+dir);
76 }
77 }
78 private ArrayList<Pixel> listPixels = new ArrayList<Pixel>();
79
80 // 5 6 7
81 // \|/
82 // 4-*-0 'dir' index vs pixel direction
83 // /|\
84 // 3 2 1
85 private int[] dirsX = new int[] {1,1,0,-1,-1,-1,0,1};
86 private int[] dirsY = new int[] {0,1,1,1,0,-1,-1,-1};
87
88 private int orange = Color.ORANGE.getRGB(); // new color of pixels ending nowhere (cul-de-sac)
89 BuildingsImageModifier bim = new BuildingsImageModifier();
90
91 private static final int cMaxnode = 10000;
92 private static final double cDistanceForOptimization = 0.5;
93 private double snapDistance = Main.pref.getDouble("cadastrewms.snap-distance", 25); // in centimeters
94 private double SimplifyFactor = 0.1;
95
96 private double snapDistanceSq = snapDistance*snapDistance;
97 private double dx, dy;
98
99 public Buildings(MapFrame mapFrame) {
100 super(tr("Grab buildings"), "buildings",
101 tr("Extract building on click (vector images only)"),
102 Shortcut.registerShortcut("mapmode:buildings", tr("Mode: {0}", tr("Buildings")), KeyEvent.VK_E, Shortcut.GROUP_EDIT),
103 mapFrame, ImageProvider.getCursor("normal", "move"));
104 }
105
106 @Override public void enterMode() {
107 super.enterMode();
108 boolean atLeastOneBuildingLayer = false;
109 for (Layer layer : Main.map.mapView.getAllLayers()) {
110 if (layer instanceof WMSLayer && ((WMSLayer)layer).isBuildingsOnly()) {
111 atLeastOneBuildingLayer = true;
112 break;
113 }
114 }
115 if (atLeastOneBuildingLayer && Main.main.getCurrentDataSet() != null) {
116 Main.map.mapView.addMouseListener(this);
117 Main.map.mapView.addMouseMotionListener(this);
118 } else {
119 JOptionPane.showMessageDialog(Main.parent,tr("This feature requires (at least) one special cadastre\nBuildings layer and an OSM data layer."));
120 exitMode();
121 Main.map.selectMapMode((MapMode)Main.map.getDefaultButtonAction());
122 }
123 }
124
125 @Override public void exitMode() {
126 super.exitMode();
127 Main.map.mapView.removeMouseListener(this);
128 Main.map.mapView.removeMouseMotionListener(this);
129 }
130
131 @Override
132 public void mousePressed(MouseEvent e) {
133 if (e.getButton() != MouseEvent.BUTTON1)
134 return;
135 selectedImage = null;
136 // ctrl = do not merge the new polygon with adjacent elements
137 boolean ctrl = (e.getModifiers() & ActionEvent.CTRL_MASK) != 0;
138 // shift = do not use the parcel as a separator
139 boolean shift = (e.getModifiers() & ActionEvent.SHIFT_MASK) != 0;
140 // boolean alt = (e.getModifiers() & ActionEvent.ALT_MASK) != 0;
141 for (Layer layer : Main.map.mapView.getAllLayers()) {
142 if (layer.isVisible() && layer instanceof WMSLayer && ((WMSLayer)layer).isBuildingsOnly() ) {
143 clickedEastNorth = Main.map.mapView.getEastNorth(e.getX(), e.getY());
144 selectedLayer = ((WMSLayer) layer);
145 selectedImage = selectedLayer.findImage(clickedEastNorth);
146 }
147 }
148 if (selectedImage != null) {
149 int x = (int)((clickedEastNorth.east() - selectedImage.min.east())*selectedImage.getPixelPerEast());
150 int y = selectedImage.image.getHeight() - (int)((clickedEastNorth.north() - selectedImage.min.north())*selectedImage.getPixelPerNorth());
151 int rgb = selectedImage.image.getRGB(x, y);
152 System.out.println("image found"+", x="+x+", y="+y+", RGB="+rgb);
153 boolean clickOnRoof = bim.isRoofColor(rgb, shift);
154 boolean clickOnBuilding = bim.isBuildingColor(rgb, shift);
155 if (clickOnRoof || clickOnBuilding) {
156 if (traceBuilding(x, y, clickOnBuilding, shift) && listPixels.size() > 3) {
157 Way wayToCreate = new Way();
158 Way way2 = new Way();
159 double pPE = selectedImage.getPixelPerEast();
160 double pPN = selectedImage.getPixelPerNorth();
161 for (int i=0; i < listPixels.size(); i++) {
162 EastNorth en = new EastNorth(selectedImage.min.east() + ((listPixels.get(i).p.x + 0.5)/ pPE),
163 selectedImage.max.north() - ((listPixels.get(i).p.y + 0.5)/ pPN));
164 Node nodeToAdd = new Node(Main.proj.eastNorth2latlon(en));
165 wayToCreate.addNode(nodeToAdd);
166 }
167 wayToCreate.addNode(wayToCreate.getNode(0)); // close the way
168 new SimplifyWay().simplifyWay(wayToCreate, SimplifyFactor);
169 // move the node closing the loop and simplify again
170 for (int i = 1; i < wayToCreate.getNodesCount(); i++) {
171 way2.addNode(wayToCreate.getNode(i));
172 }
173 way2.addNode(way2.getNode(0));
174 new SimplifyWay().simplifyWay(way2, SimplifyFactor);
175 simplifyAngles(way2);
176 Way wayToAdd = new Way();
177 Collection<Command> cmds = new LinkedList<Command>();
178 if (ctrl) {
179 for (int i = 0; i < way2.getNodesCount()-1; i++) {
180 wayToAdd.addNode(way2.getNode(i));
181 cmds.add(new AddCommand(wayToAdd.getNode(i)));
182 }
183 wayToAdd.addNode(wayToAdd.getNode(0)); // close the polygon !
184 } else {
185 for (int i = 0; i < way2.getNodesCount()-1; i++) {
186 Node nearestNode = getNearestNode(way2.getNode(i));
187 if (nearestNode == null) {
188 // check if we can join new node to existing ways
189 List<WaySegment> wss = getNearestWaySegments(way2.getNode(i));
190 wayToAdd.addNode(way2.getNode(i));
191 cmds.add(new AddCommand(way2.getNode(i)));
192 if (wss.size() > 0) {
193 cmds.add(new MoveCommand(way2.getNode(i), dx, dy));
194 joinNodeToExistingWays(wss, way2.getNode(i), cmds);
195 }
196 } else {
197 // replace new node by an existing nearest node
198 wayToAdd.addNode(nearestNode);
199 cmds.add(new MoveCommand(nearestNode, dx, dy));
200 }
201 }
202 wayToAdd.addNode(wayToAdd.getNode(0)); // close the polygon !
203 for (int i = 1; i < wayToAdd.getNodesCount(); i++) {
204 Node nodeToJoin = existingNodesInNewSegment(wayToAdd.getNode(i-1), wayToAdd.getNode(i), wayToAdd);
205 // check if we join new way to existing nodes
206 if (nodeToJoin != null) {
207 List<WaySegment> wss = new LinkedList<WaySegment>();
208 wss.add(new WaySegment(wayToAdd, i-1));
209 wayToAdd = joinNodeToExistingWays(wss, nodeToJoin, cmds);
210 cmds.add(new MoveCommand(nodeToJoin, dx, dy));
211 i--; // re-assess the new segment (perhaps several nodes to join)
212 }
213 }
214 }
215 cmds.add(new AddCommand(wayToAdd));
216 if (clickOnBuilding)
217 addBuildingTags(cmds, wayToAdd);
218 if (clickOnRoof) {
219 addRoofTags(cmds, wayToAdd);
220 }
221 Main.main.undoRedo.add(new SequenceCommand(tr("Create building"), cmds));
222 getCurrentDataSet().setSelected(wayToAdd);
223 Main.map.repaint();
224 }
225 }
226 }
227 }
228
229 @Override public void mouseDragged(MouseEvent e) {
230 }
231
232 @Override public void mouseReleased(MouseEvent e) {
233 }
234
235 public void mouseEntered(MouseEvent e) {
236 }
237 public void mouseExited(MouseEvent e) {
238 }
239 public void mouseMoved(MouseEvent e) {
240 }
241
242 @Override public void mouseClicked(MouseEvent e) {
243 }
244
245 private void addBuildingTags(Collection<Command> cmds, Way wayToAdd) {
246 cmds.add(new ChangePropertyCommand(wayToAdd, "building", "yes"));
247 }
248
249 private void addRoofTags(Collection<Command> cmds, Way wayToAdd) {
250 cmds.add(new ChangePropertyCommand(wayToAdd, "building", "yes"));
251 cmds.add(new ChangePropertyCommand(wayToAdd, "wall", "no"));
252 }
253
254 private boolean traceBuilding (int x, int y, boolean buildingColors, boolean ignoreParcels) {
255 // search start point at same x but smallest y (upper border on the screen)
256 int startY = 0; int startX = x;
257 while (y > 0) {
258 y--;
259 if (!bim.isBuildingOrRoofColor(selectedImage.image, x, y, buildingColors, ignoreParcels)) {
260 System.out.println("at "+x+","+y+" color was "+selectedImage.image.getRGB(x,y));
261 y++;
262 startY = y;
263 break;
264 }
265 }
266 if (startY == 0) {
267 System.out.println("border not found");
268 return false;
269 } else
270 System.out.println("start at x="+startX+", y="+startY);
271 listPixels.clear();
272 int test_x = 0;
273 int test_y = 0;
274 int new_dir = 0;
275 addPixeltoList(x, y, new_dir);
276 int last_dir = 1;
277 for(int i = 0; i < cMaxnode; i++){
278 //System.out.println("node "+i);
279 for(int d = 1; d <= this.dirsY.length; d++){
280 new_dir = (last_dir + d + 4) % 8;
281 test_x = x + this.dirsX[new_dir];
282 test_y = y + this.dirsY[new_dir];
283 if (test_x < 0 || test_x >= selectedImage.image.getWidth() ||
284 test_y < 0 || test_y >= selectedImage.image.getHeight()){
285 System.out.println("Outside image");
286 return false;
287 }
288 if (bim.isBuildingOrRoofColor(selectedImage.image, test_x, test_y, buildingColors, ignoreParcels)){
289 System.out.println("building color at "+test_x+","+test_y+" new_dir="+new_dir);
290 break;
291 }
292
293 if(d == this.dirsY.length-1){
294 System.out.println("Got stuck at "+x+","+y);
295 // cul-de-sac : disable current pixel and move two steps back
296 selectedImage.image.setRGB(x, y, orange);
297 if (removeTwoLastPixelsFromList()) {
298 x = listPixels.get(listPixels.size()-1).p.x;
299 y = listPixels.get(listPixels.size()-1).p.y;
300 last_dir = listPixels.get(listPixels.size()-1).dir;
301 System.out.println("return at "+x+","+y+" and try again");
302 d = 1;
303 continue;
304 } else {
305 System.out.println("cannot try another way");
306 return false;
307 }
308 }
309 }
310// if (last_dir == new_dir)
311// // Same direction. First simplification by removing previous pixel.
312// listPixels.remove(listPixels.size()-1);
313 last_dir = new_dir;
314 // Set the pixel we found as current
315 x = test_x;
316 y = test_y;
317 // Break the loop if we managed to get back to our starting point
318 if (x == startX && y == startY) {
319 System.out.println("loop closed at "+x+","+y+", exit");
320 break;
321 } else if (listPixels.contains(new Pixel(x, y, 0))){
322 int j = listPixels.indexOf(new Pixel(x, y, 0));
323 int l = listPixels.size();
324 for (int k = j; k < l; k++)
325 listPixels.remove(j);
326 }
327 addPixeltoList(x, y, new_dir);
328 }
329 inflate();
330 System.out.println("list size="+listPixels.size());
331 return true;
332 }
333
334 private void addPixeltoList(int x, int y, int dir) {
335 listPixels.add( new Pixel(x, y, dir));
336 System.out.println("added pixel at "+x+","+y);
337 }
338
339 private void inflate() {
340 // TODO
341 if (listPixels.size() > 1) {
342// for (int i=1; i<listPixels.size()-1; i++) {
343// int delta_dir = Math.abs((listPixels.get(i+1).dir - listPixels.get(i-1).dir + 8)%8);
344// if (delta_dir > 1 && delta_dir < 4) {
345// System.out.println(listPixels.get(i).dir);
346// int j = i;
347// if (listPixels.get(i).dir == 0 || listPixels.get(i).dir == 1 || listPixels.get(i).dir == 4 || listPixels.get(i).dir == 2)
348// j = i-1;
349// listPixels.get(j).toKeep = true;
350// i+=2;
351// selectedImage.image.setRGB(listPixels.get(j).p.x, listPixels.get(j).p.y, Color.GREEN.getRGB());
352// }
353// }
354 ArrayList<Pixel> newList = new ArrayList<Pixel>();
355 for (int i=0; i<listPixels.size(); i++) {
356// selectedImage.image.setRGB(listPixels.get(i).p.x, listPixels.get(i).p.y, Color.GREEN.getRGB());
357 boolean inflatedPixel = false;
358 for (int j=0; j<3; j++) {
359 if ((i+j-1) > 0 && (i+j-1) < listPixels.size()) {
360 int inflate_dir = (listPixels.get(i+j-1).dir+6)%8;
361 Pixel p = new Pixel(listPixels.get(i).p.x+dirsX[inflate_dir],
362 listPixels.get(i).p.y+dirsY[inflate_dir],
363 listPixels.get(i).dir);
364 if (bim.isParcelColor(selectedImage.image, p.p.x, p.p.y)) {
365 if (!newList.contains(p))
366 newList.add(p);
367 inflatedPixel = true;
368 }
369 }
370 }
371 if (!inflatedPixel) {
372 if (!newList.contains(listPixels.get(i)))
373 newList.add(listPixels.get(i));
374 }
375 }
376 listPixels = newList;
377 }
378 }
379
380 private boolean removeTwoLastPixelsFromList() {
381 if (listPixels.size() > 2) {
382 System.out.println("remove "+listPixels.get(listPixels.size()-1).p.x + ","+listPixels.get(listPixels.size()-1).p.y);
383 listPixels.remove(listPixels.size()-1);
384 System.out.println("remove "+listPixels.get(listPixels.size()-1).p.x + ","+listPixels.get(listPixels.size()-1).p.y);
385 listPixels.remove(listPixels.size()-1);
386 return true;
387 }
388 return false;
389 }
390
391 private BBox getSnapDistanceBBox(Node n) {
392 return new BBox(Main.proj.eastNorth2latlon(new EastNorth(n.getEastNorth().east() - snapDistance, n.getEastNorth().north() - snapDistance)),
393 Main.proj.eastNorth2latlon(new EastNorth(n.getEastNorth().east() + snapDistance, n.getEastNorth().north() + snapDistance)));
394 }
395
396 private Point getPointInCm(Node n) {
397 return new Point(new Double(n.getEastNorth().getX()*100).intValue(),
398 new Double(n.getEastNorth().getY()*100).intValue());
399 }
400
401 public Node getNearestNode(Node newNode) {
402 Point newPoint = getPointInCm(newNode);
403 DataSet ds = getCurrentDataSet();
404 if (ds == null)
405 return null;
406
407 double minDistanceSq = snapDistanceSq;
408 Node minNode = null;
409 for (Node n : ds.searchNodes(getSnapDistanceBBox(newNode))) {
410 if (!n.isUsable()) {
411 continue;
412 }
413 Point sp = new Point(new Double(n.getEastNorth().getX()*100).intValue(),
414 new Double(n.getEastNorth().getY()*100).intValue());
415 double dist = newPoint.distanceSq(sp); // in centimeter !
416 if (dist < minDistanceSq) {
417 minDistanceSq = dist;
418 minNode = n;
419 }
420 // when multiple nodes on one point, prefer new or selected nodes
421 else if (dist == minDistanceSq && minNode != null
422 && ((n.isNew() && ds.isSelected(n))
423 || (!ds.isSelected(minNode) && (ds.isSelected(n) || n.isNew())))) {
424 minNode = n;
425 }
426 }
427 if (minNode != null) {
428 dx = (newNode.getEastNorth().getX() - minNode.getEastNorth().getX())/2;
429 dy = (newNode.getEastNorth().getY() - minNode.getEastNorth().getY())/2;
430 }
431 return minNode;
432 }
433
434 private List<WaySegment> getNearestWaySegments(Node newNode) {
435 Point newPoint = new Point(new Double(newNode.getEastNorth().getX()*100).intValue(),
436 new Double(newNode.getEastNorth().getY()*100).intValue());
437 TreeMap<Double, List<WaySegment>> nearest = new TreeMap<Double, List<WaySegment>>();
438 DataSet ds = getCurrentDataSet();
439 if (ds == null)
440 return null;
441
442 for (Way w : ds.searchWays(getSnapDistanceBBox(newNode))) {
443 if (!w.isUsable()) {
444 continue;
445 }
446 Node lastN = null;
447 int i = -2;
448 for (Node n : w.getNodes()) {
449 i++;
450 if (n.isDeleted() || n.isIncomplete()) {
451 continue;
452 }
453 if (lastN == null) {
454 lastN = n;
455 continue;
456 }
457
458 Point A = getPointInCm(lastN);
459 Point B = getPointInCm(n);
460 double c = A.distanceSq(B);
461 double a = newPoint.distanceSq(B);
462 double b = newPoint.distanceSq(A);
463 double perDist = a - (a - b + c) * (a - b + c) / 4 / c;
464 if (perDist < snapDistanceSq && a < c + snapDistanceSq && b < c + snapDistanceSq) {
465 if (ds.isSelected(w)) {
466 perDist -= 0.00001;
467 }
468 List<WaySegment> l;
469 if (nearest.containsKey(perDist)) {
470 l = nearest.get(perDist);
471 } else {
472 l = new LinkedList<WaySegment>();
473 nearest.put(perDist, l);
474 }
475 double ratio = A.distance(newPoint)/A.distance(B);
476 Point perP = new Point(A.x+new Double((B.x-A.x)*ratio).intValue(),
477 A.y+new Double((B.y-A.y)*ratio).intValue());
478 dx = (perP.x-newPoint.x)/200.0; // back to meters this time and whole distance by two
479 dy = (perP.y-newPoint.y)/200.0;
480// System.out.println(angle+","+ ratio+","+perP );
481 l.add(new WaySegment(w, i));
482 }
483
484 lastN = n;
485 }
486 }
487 ArrayList<WaySegment> nearestList = new ArrayList<WaySegment>();
488 for (List<WaySegment> wss : nearest.values()) {
489 nearestList.addAll(wss);
490 }
491 return nearestList;
492 }
493
494 private Node existingNodesInNewSegment(Node n1, Node n2, Way way) {
495 double minx = Math.min(n1.getEastNorth().getX(), n2.getEastNorth().getX())*100;
496 double miny = Math.min(n1.getEastNorth().getY(), n2.getEastNorth().getY())*100;
497 double maxx = Math.max(n1.getEastNorth().getX(), n2.getEastNorth().getX())*100;
498 double maxy = Math.max(n1.getEastNorth().getY(), n2.getEastNorth().getY())*100;
499// if ((maxx-minx)/2 < snapDistance && (maxy-miny)/2 < snapDistance) {
500// return null;
501// }
502 BBox bbox = new BBox( Main.proj.eastNorth2latlon(new EastNorth((minx-snapDistance)/100, (miny-snapDistance)/100)),
503 Main.proj.eastNorth2latlon(new EastNorth((maxx+snapDistance)/100, (maxy+snapDistance)/100)));
504 DataSet ds = getCurrentDataSet();
505 if (ds == null) {
506 return null;
507 }
508 Node ret = null;
509 List<Node> nodesInBbox = ds.searchNodes(bbox);
510 for (Node n:nodesInBbox) {
511 Point A = getPointInCm(n1);
512 Point B = getPointInCm(n2);
513 Point existingPoint = getPointInCm(n);
514 double c = A.distanceSq(B);
515 double a = existingPoint.distanceSq(B);
516 double b = existingPoint.distanceSq(A);
517 double perDist = a - (a - b + c) * (a - b + c) / 4 / c;
518 if (perDist < snapDistanceSq && a < c + snapDistanceSq && b < c + snapDistanceSq
519 && n.isUsable() && !way.getNodes().contains(n)) {
520 ret = n;
521 // shift the existing node to the half distance of the joined new segment
522 double ratio = A.distance(existingPoint)/A.distance(B);
523 Point perP = new Point(A.x+new Double((B.x-A.x)*ratio).intValue(),
524 A.y+new Double((B.y-A.y)*ratio).intValue());
525 dx = (perP.x-existingPoint.x)/200.0; // back to meters this time and whole distance by two
526 dy = (perP.y-existingPoint.y)/200.0;
527 break;
528 }
529 }
530// System.out.println("Found "+nodesInBbox.size()+", join node "+ret+" to new segment; "+Main.proj.latlon2eastNorth(bbox.getBottomRight())+","+Main.proj.latlon2eastNorth(bbox.getTopLeft()));
531 return ret;
532 }
533
534 private Way joinNodeToExistingWays(List<WaySegment> wss, Node newNode, Collection<Command> cmds) {
535 HashMap<Way, List<Integer>> insertPoints = new HashMap<Way, List<Integer>>();
536 for (WaySegment ws : wss) {
537 List<Integer> is;
538 if (insertPoints.containsKey(ws.way)) {
539 is = insertPoints.get(ws.way);
540 } else {
541 is = new ArrayList<Integer>();
542 insertPoints.put(ws.way, is);
543 }
544
545 if (ws.way.getNode(ws.lowerIndex) != newNode && ws.way.getNode(ws.lowerIndex+1) != newNode) {
546 is.add(ws.lowerIndex);
547 }
548 }
549
550 Way wnew = null;
551 for (Map.Entry<Way, List<Integer>> insertPoint : insertPoints.entrySet()) {
552 List<Integer> is = insertPoint.getValue();
553 if (is.size() == 0)
554 continue;
555
556 Way w = insertPoint.getKey();
557 List<Node> nodesToAdd = w.getNodes();
558 pruneSuccsAndReverse(is);
559 for (int i : is) {
560 nodesToAdd.add(i+1, newNode);
561 }
562 wnew = new Way(w);
563 wnew.setNodes(nodesToAdd);
564 cmds.add(new ChangeCommand(w, wnew));
565 }
566 return wnew;
567 }
568
569 private static void pruneSuccsAndReverse(List<Integer> is) {
570 HashSet<Integer> is2 = new HashSet<Integer>();
571 for (int i : is) {
572 if (!is2.contains(i - 1) && !is2.contains(i + 1)) {
573 is2.add(i);
574 }
575 }
576 is.clear();
577 is.addAll(is2);
578 Collections.sort(is);
579 Collections.reverse(is);
580 }
581
582 /*
583 * The standard simplifier leaves sometimes closed nodes at buildings corners.
584 * We remove here the node not altering the building angle.
585 */
586 private void simplifyAngles(Way way){
587 for (int i=1; i<way.getNodes().size(); i++){
588 Node n1 = way.getNode(i-1);
589 Node n2 = way.getNode(i);
590 double dist = getPointInCm(n1).distance(getPointInCm(n2))/100;
591// System.out.println("dist="+dist+":"+(dist < cDistanceForOptimization));
592 if (dist < cDistanceForOptimization) {
593 Node n0, n3;
594 if (i > 1)
595 n0 = way.getNode(i-2);
596 else
597 n0 = way.getNode(way.getNodes().size()-1);
598 if (i < way.getNodes().size()-1)
599 n3 = way.getNode(i+1);
600 else
601 n3 = way.getNode(0);
602 double angle1 = AngleOfView(n1.getCoor().getX(), n1.getCoor().getY(),
603 n0.getCoor().getX(), n0.getCoor().getY(),
604 n2.getCoor().getX(), n2.getCoor().getY());
605// System.out.println("angle n0,n1,n2="+(angle1*180/Math.PI));
606 double angle2 = AngleOfView(n2.getCoor().getX(), n2.getCoor().getY(),
607 n1.getCoor().getX(), n1.getCoor().getY(),
608 n3.getCoor().getX(), n3.getCoor().getY());
609// System.out.println("angle n1,n2,n3="+(angle2*180/Math.PI));
610 if (angle1 > Math.PI*0.9 && angle1 < Math.PI*1.1) {
611 way.removeNode(n1);
612 System.out.println("remove n1");
613 } else if (angle2 > Math.PI*0.9 && angle2 < Math.PI*1.1) {
614 way.removeNode(n2);
615 System.out.println("remove n2");
616 } else
617 System.out.println("no angle near PI");
618 }
619 }
620 }
621
622 private double AngleOfView ( double ViewPt_X, double ViewPt_Y,
623 double Pt1_X, double Pt1_Y,
624 double Pt2_X, double Pt2_Y ) {
625 double a1, b1, a2, b2, a, b, t, cosinus ;
626 a1 = Pt1_X - ViewPt_X ;
627 a2 = Pt1_Y - ViewPt_Y ;
628 b1 = Pt2_X - ViewPt_X ;
629 b2 = Pt2_Y - ViewPt_Y ;
630 a = Math.sqrt( (a1*a1) + (a2*a2) );
631 b = Math.sqrt ( (b1*b1) + (b2*b2) );
632 if ( (a == 0.0) || (b == 0.0) )
633 return (0.0) ;
634 cosinus = (a1*b1+a2*b2) / (a*b) ;
635 t = Math.acos ( cosinus );
636 //t = t * 180.0 / Math.PI ;
637 return (t);
638 }
639
640 /*
641 * coming from SimplifyWayAction
642 */
643// private boolean isRequiredNode(Way way, Node node) {
644// boolean isRequired = Collections.frequency(way.getNodes(), node) > 1;
645// if (! isRequired) {
646// List<OsmPrimitive> parents = new LinkedList<OsmPrimitive>();
647// parents.addAll(node.getReferrers());
648// parents.remove(way);
649// isRequired = !parents.isEmpty();
650// }
651// if (!isRequired) {
652// isRequired = node.isTagged();
653// }
654// return isRequired;
655// }
656}
Note: See TracBrowser for help on using the repository browser.