source: osm/applications/editors/josm/plugins/utilsplugin/src/UtilsPlugin/SimplifyWayAction.java@ 10311

Last change on this file since 10311 was 9370, checked in by frederik, 17 years ago

changed default max-error for SimplifyWay to 3 metres (was 50)

File size: 4.6 KB
Line 
1package UtilsPlugin;
2
3import static org.openstreetmap.josm.tools.I18n.tr;
4
5import java.awt.event.ActionEvent;
6import java.awt.event.KeyEvent;
7import java.util.ArrayList;
8import java.util.Collection;
9import java.util.Collections;
10import java.util.HashSet;
11import java.util.LinkedList;
12import java.util.List;
13
14import org.openstreetmap.josm.Main;
15import org.openstreetmap.josm.command.ChangeCommand;
16import org.openstreetmap.josm.command.Command;
17import org.openstreetmap.josm.command.DeleteCommand;
18import org.openstreetmap.josm.command.SequenceCommand;
19import org.openstreetmap.josm.data.coor.LatLon;
20import org.openstreetmap.josm.data.osm.Node;
21import org.openstreetmap.josm.data.osm.OsmPrimitive;
22import org.openstreetmap.josm.data.osm.Way;
23import org.openstreetmap.josm.data.osm.visitor.CollectBackReferencesVisitor;
24
25import org.openstreetmap.josm.data.osm.DataSet;
26import org.openstreetmap.josm.actions.JosmAction;
27
28public class SimplifyWayAction extends JosmAction {
29 public SimplifyWayAction() {
30 super(tr("Simplify Way"), "simplify",
31 tr("Delete unnecessary nodes from a way."), KeyEvent.VK_Y, KeyEvent.CTRL_MASK | KeyEvent.SHIFT_MASK, true);
32 }
33
34 public void actionPerformed(ActionEvent e) {
35 Collection<OsmPrimitive> selection = Main.ds.getSelected();
36
37 for (OsmPrimitive prim : selection) {
38 if (prim instanceof Way) {
39 simplifyWay((Way) prim);
40 }
41 }
42 }
43
44 public void simplifyWay(Way w) {
45 double threshold = Double.parseDouble(
46 Main.pref.get("simplify-way.max-error", "3"));
47
48 Way wnew = new Way(w);
49
50 int toI = wnew.nodes.size() - 1;
51 for (int i = wnew.nodes.size() - 1; i >= 0; i--) {
52 CollectBackReferencesVisitor backRefsV =
53 new CollectBackReferencesVisitor(Main.ds, false);
54 backRefsV.visit(wnew.nodes.get(i));
55 boolean used = false;
56 if (backRefsV.data.size() == 1) {
57 used = Collections.frequency(
58 w.nodes, wnew.nodes.get(i)) > 1;
59 } else {
60 backRefsV.data.remove(w);
61 used = !backRefsV.data.isEmpty();
62 }
63 if (!used) used = wnew.nodes.get(i).tagged;
64
65 if (used) {
66 simplifyWayRange(wnew, i, toI, threshold);
67 toI = i;
68 }
69 }
70 simplifyWayRange(wnew, 0, toI, threshold);
71
72 HashSet<Node> delNodes = new HashSet<Node>();
73 delNodes.addAll(w.nodes);
74 delNodes.removeAll(wnew.nodes);
75
76 if (wnew.nodes.size() != w.nodes.size()) {
77 Collection<Command> cmds = new LinkedList<Command>();
78 cmds.add(new ChangeCommand(w, wnew));
79 cmds.add(new DeleteCommand(delNodes));
80 Main.main.undoRedo.add(
81 new SequenceCommand(tr("Simplify Way (remove {0} nodes)",
82 delNodes.size()),
83 cmds));
84 Main.map.repaint();
85 }
86 }
87
88 public void simplifyWayRange(Way wnew, int from, int to, double thr) {
89 if (to - from >= 2) {
90 ArrayList<Node> ns = new ArrayList<Node>();
91 simplifyWayRange(wnew, from, to, ns, thr);
92 for (int j = to-1; j > from; j--) wnew.nodes.remove(j);
93 wnew.nodes.addAll(from+1, ns);
94 }
95 }
96
97 /*
98 * Takes an interval [from,to] and adds nodes from (from,to) to ns.
99 * (from and to are indices of wnew.nodes.)
100 */
101 public void simplifyWayRange(Way wnew, int from, int to, ArrayList<Node> ns, double thr) {
102 Node fromN = wnew.nodes.get(from), toN = wnew.nodes.get(to);
103
104 int imax = -1;
105 double xtemax = 0;
106 for (int i = from+1; i < to; i++) {
107 Node n = wnew.nodes.get(i);
108 double xte = Math.abs(EARTH_RAD * xtd(
109 fromN.coor.lat() * Math.PI/180, fromN.coor.lon() * Math.PI/180,
110 toN.coor.lat() * Math.PI/180, toN.coor.lon() * Math.PI/180,
111 n.coor.lat() * Math.PI/180, n.coor.lon() * Math.PI/180));
112 if (xte > xtemax) {
113 xtemax = xte;
114 imax = i;
115 }
116 }
117
118 if (imax != -1 && xtemax >= thr) {
119 simplifyWayRange(wnew, from, imax, ns, thr);
120 ns.add(wnew.nodes.get(imax));
121 simplifyWayRange(wnew, imax, to, ns, thr);
122 }
123 }
124
125 public static double EARTH_RAD = 6378137.0;
126
127 /* From Aviaton Formulary v1.3
128 * http://williams.best.vwh.net/avform.htm
129 */
130 public static double dist(double lat1, double lon1, double lat2, double lon2) {
131 return 2*Math.asin(Math.sqrt(Math.pow(Math.sin((lat1-lat2)/2), 2) +
132 Math.cos(lat1)*Math.cos(lat2)*Math.pow(Math.sin((lon1-lon2)/2), 2)));
133 }
134
135 public static double course(double lat1, double lon1, double lat2, double lon2) {
136 return Math.atan2(Math.sin(lon1-lon2)*Math.cos(lat2),
137 Math.cos(lat1)*Math.sin(lat2)-Math.sin(lat1)*Math.cos(lat2)*Math.cos(lon1-lon2)) % (2*Math.PI);
138 }
139
140 public static double xtd(double lat1, double lon1, double lat2, double lon2, double lat3, double lon3) {
141 double dist_AD = dist(lat1, lon1, lat3, lon3);
142 double crs_AD = course(lat1, lon1, lat3, lon3);
143 double crs_AB = course(lat1, lon1, lat2, lon2);
144 return Math.asin(Math.sin(dist_AD)*Math.sin(crs_AD-crs_AB));
145 }
146}
Note: See TracBrowser for help on using the repository browser.