source: josm/src/org/openstreetmap/josm/data/osm/visitor/MergeVisitor.java@ 60

Last change on this file since 60 was 60, checked in by imi, 18 years ago
  • fixed load of action attribute (preserve changes)
  • fixed exception when merging ways with different number of segments
File size: 6.2 KB
Line 
1package org.openstreetmap.josm.data.osm.visitor;
2
3import java.util.HashMap;
4import java.util.Iterator;
5import java.util.LinkedList;
6import java.util.Map;
7
8import org.openstreetmap.josm.data.osm.DataSet;
9import org.openstreetmap.josm.data.osm.Key;
10import org.openstreetmap.josm.data.osm.LineSegment;
11import org.openstreetmap.josm.data.osm.Node;
12import org.openstreetmap.josm.data.osm.OsmPrimitive;
13import org.openstreetmap.josm.data.osm.Track;
14
15/**
16 * A visitor that get a data set at construction time and merge every visited object
17 * into it.
18 *
19 * @author imi
20 */
21public class MergeVisitor implements Visitor {
22
23 private final DataSet ds;
24
25 /**
26 * A list of all nodes that got replaced with other nodes.
27 * Key is the node in the other's dataset and the value is the one that is now
28 * in ds.nodes instead.
29 */
30 private final Map<Node, Node> mergedNodes = new HashMap<Node, Node>();
31 /**
32 * A list of all line segments that got replaced with others.
33 * Key is the segment in the other's dataset and the value is the one that is now
34 * in ds.lineSegments.
35 */
36 private final Map<LineSegment, LineSegment> mergedLineSegments = new HashMap<LineSegment, LineSegment>();
37
38 public MergeVisitor(DataSet ds) {
39 this.ds = ds;
40 }
41
42 /**
43 * Merge the node if the id matches with any of the internal set or if
44 * either id is zero, merge if lat/lon matches.
45 */
46 public void visit(Node otherNode) {
47 Node myNode = null;
48 for (Node n : ds.nodes) {
49 if (match(n, otherNode)) {
50 myNode = n;
51 break;
52 }
53 }
54 if (myNode == null)
55 ds.nodes.add(otherNode);
56 else {
57 mergedNodes.put(otherNode, myNode);
58 mergeCommon(myNode, otherNode);
59 if (myNode.modified && !otherNode.modified)
60 return;
61 if (!myNode.coor.equalsLatLonEpsilon(otherNode.coor)) {
62 myNode.coor = otherNode.coor;
63 myNode.modified = otherNode.modified;
64 }
65 }
66 }
67
68 /**
69 * Merge the line segment if id matches or if both nodes are the same (and the
70 * id is zero of either segment). Nodes are the "same" when they @see match
71 */
72 public void visit(LineSegment otherLs) {
73 LineSegment myLs = null;
74 for (LineSegment ls : ds.lineSegments) {
75 if (match(otherLs, ls)) {
76 myLs = ls;
77 break;
78 }
79 }
80 if (myLs == null)
81 ds.lineSegments.add(otherLs);
82 else {
83 mergedLineSegments.put(otherLs, myLs);
84 mergeCommon(myLs, otherLs);
85 if (myLs.modified && !otherLs.modified)
86 return;
87 if (!match(myLs.start, otherLs.start)) {
88 myLs.start = otherLs.start;
89 myLs.modified = otherLs.modified;
90 }
91 if (!match(myLs.end, otherLs.end)) {
92 myLs.end = otherLs.end;
93 myLs.modified = otherLs.modified;
94 }
95 }
96 }
97
98 /**
99 * Merge the track if id matches or if all line segments matches and the
100 * id is zero of either track.
101 */
102 public void visit(Track otherTrack) {
103 Track myTrack = null;
104 for (Track t : ds.tracks) {
105 if (match(otherTrack, t)) {
106 myTrack = t;
107 break;
108 }
109 }
110 if (myTrack == null)
111 ds.tracks.add(otherTrack);
112 else {
113 mergeCommon(myTrack, otherTrack);
114 if (myTrack.modified && !otherTrack.modified)
115 return;
116 boolean same = true;
117 Iterator<LineSegment> it = otherTrack.segments.iterator();
118 for (LineSegment ls : myTrack.segments) {
119 if (!match(ls, it.next()))
120 same = false;
121 }
122 if (!same) {
123 myTrack.segments.clear();
124 myTrack.segments.addAll(otherTrack.segments);
125 myTrack.modified = otherTrack.modified;
126 }
127 }
128 }
129
130 public void visit(Key k) {
131 //TODO: Key doesn't really fit the OsmPrimitive concept!
132 }
133
134 /**
135 * Postprocess the dataset and fix all merged references to point to the actual
136 * data.
137 */
138 public void fixReferences() {
139 for (LineSegment ls : ds.lineSegments) {
140 if (mergedNodes.containsKey(ls.start))
141 ls.start = mergedNodes.get(ls.start);
142 if (mergedNodes.containsKey(ls.end))
143 ls.end = mergedNodes.get(ls.end);
144 }
145 for (Track t : ds.tracks) {
146 boolean replacedSomething = false;
147 LinkedList<LineSegment> newSegments = new LinkedList<LineSegment>();
148 for (LineSegment ls : t.segments) {
149 LineSegment otherLs = mergedLineSegments.get(ls);
150 newSegments.add(otherLs == null ? ls : otherLs);
151 if (otherLs != null)
152 replacedSomething = true;
153 }
154 if (replacedSomething) {
155 t.segments.clear();
156 t.segments.addAll(newSegments);
157 }
158 for (LineSegment ls : t.segments) {
159 if (mergedNodes.containsKey(ls.start))
160 ls.start = mergedNodes.get(ls.start);
161 if (mergedNodes.containsKey(ls.end))
162 ls.end = mergedNodes.get(ls.end);
163 }
164 }
165 }
166
167 /**
168 * @return Whether the nodes matches (in sense of "be mergable").
169 */
170 private boolean match(Node n1, Node n2) {
171 if (n1.id == 0 || n2.id == 0)
172 return n1.coor.equalsLatLonEpsilon(n2.coor);
173 return n1.id == n2.id;
174 }
175
176 /**
177 * @return Whether the line segments matches (in sense of "be mergable").
178 */
179 private boolean match(LineSegment ls1, LineSegment ls2) {
180 if (ls1.id == 0 || ls2.id == 0)
181 return match(ls1.start, ls2.start) && match(ls1.end, ls2.end);
182 return ls1.id == ls2.id;
183 }
184
185 /**
186 * @return Whether the tracks matches (in sense of "be mergable").
187 */
188 private boolean match(Track t1, Track t2) {
189 if (t1.id == 0 || t2.id == 0) {
190 if (t1.segments.size() != t2.segments.size())
191 return false;
192 Iterator<LineSegment> it = t1.segments.iterator();
193 for (LineSegment ls : t2.segments)
194 if (!match(ls, it.next()))
195 return false;
196 return true;
197 }
198 return t1.id == t2.id;
199 }
200
201 /**
202 * Merge the common parts of an osm primitive.
203 * @param myOsm The object, the information gets merged into
204 * @param otherOsm The object, the information gets merged from
205 */
206 private void mergeCommon(OsmPrimitive myOsm, OsmPrimitive otherOsm) {
207 if (otherOsm.isDeleted())
208 myOsm.setDeleted(true);
209 if (!myOsm.modified || otherOsm.modified) {
210 if (myOsm.id == 0 && otherOsm.id != 0)
211 myOsm.id = otherOsm.id; // means not ncessary the object is now modified
212 else if (myOsm.id != 0 && otherOsm.id != 0 && otherOsm.modified)
213 myOsm.modified = true;
214 }
215 if (myOsm.modifiedProperties && !otherOsm.modifiedProperties)
216 return;
217 if (otherOsm.keys == null)
218 return;
219 if (myOsm.keys != null && myOsm.keys.entrySet().containsAll(otherOsm.keys.entrySet()))
220 return;
221 if (myOsm.keys == null)
222 myOsm.keys = otherOsm.keys;
223 else
224 myOsm.keys.putAll(otherOsm.keys);
225 myOsm.modifiedProperties = true;
226 }
227}
Note: See TracBrowser for help on using the repository browser.