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

Last change on this file since 71 was 71, checked in by imi, 18 years ago
  • refactored GpsPoint to be immutable and added LatLon and NorthEast
  • refactored Bounding Box calculations
  • various other renames
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.LineSegment;
10import org.openstreetmap.josm.data.osm.Node;
11import org.openstreetmap.josm.data.osm.OsmPrimitive;
12import org.openstreetmap.josm.data.osm.Way;
13
14/**
15 * A visitor that get a data set at construction time and merge every visited object
16 * into it.
17 *
18 * @author imi
19 */
20public class MergeVisitor implements Visitor {
21
22 private final DataSet ds;
23
24 /**
25 * A list of all nodes that got replaced with other nodes.
26 * Key is the node in the other's dataset and the value is the one that is now
27 * in ds.nodes instead.
28 */
29 private final Map<Node, Node> mergedNodes = new HashMap<Node, Node>();
30 /**
31 * A list of all line segments that got replaced with others.
32 * Key is the segment in the other's dataset and the value is the one that is now
33 * in ds.lineSegments.
34 */
35 private final Map<LineSegment, LineSegment> mergedLineSegments = new HashMap<LineSegment, LineSegment>();
36
37 public MergeVisitor(DataSet ds) {
38 this.ds = ds;
39 }
40
41 /**
42 * Merge the node if the id matches with any of the internal set or if
43 * either id is zero, merge if lat/lon matches.
44 */
45 public void visit(Node otherNode) {
46 Node myNode = null;
47 for (Node n : ds.nodes) {
48 if (match(n, otherNode)) {
49 myNode = n;
50 break;
51 }
52 }
53 if (myNode == null)
54 ds.nodes.add(otherNode);
55 else {
56 mergedNodes.put(otherNode, myNode);
57 mergeCommon(myNode, otherNode);
58 if (myNode.modified && !otherNode.modified)
59 return;
60 if (!myNode.coor.equalsEpsilon(otherNode.coor)) {
61 myNode.coor = otherNode.coor;
62 myNode.modified = otherNode.modified;
63 }
64 }
65 }
66
67 /**
68 * Merge the line segment if id matches or if both nodes are the same (and the
69 * id is zero of either segment). Nodes are the "same" when they @see match
70 */
71 public void visit(LineSegment otherLs) {
72 LineSegment myLs = null;
73 for (LineSegment ls : ds.lineSegments) {
74 if (match(otherLs, ls)) {
75 myLs = ls;
76 break;
77 }
78 }
79 if (myLs == null)
80 ds.lineSegments.add(otherLs);
81 else if (myLs.incomplete && !otherLs.incomplete) {
82 mergedLineSegments.put(otherLs, myLs);
83 myLs.cloneFrom(otherLs);
84 } else if (!otherLs.incomplete) {
85 mergedLineSegments.put(otherLs, myLs);
86 mergeCommon(myLs, otherLs);
87 if (myLs.modified && !otherLs.modified)
88 return;
89 if (!match(myLs.from, otherLs.from)) {
90 myLs.from = otherLs.from;
91 myLs.modified = otherLs.modified;
92 }
93 if (!match(myLs.to, otherLs.to)) {
94 myLs.to = otherLs.to;
95 myLs.modified = otherLs.modified;
96 }
97 }
98 }
99
100 /**
101 * Merge the way if id matches or if all line segments matches and the
102 * id is zero of either way.
103 */
104 public void visit(Way otherWay) {
105 Way myWay = null;
106 for (Way t : ds.ways) {
107 if (match(otherWay, t)) {
108 myWay = t;
109 break;
110 }
111 }
112 if (myWay == null)
113 ds.ways.add(otherWay);
114 else {
115 mergeCommon(myWay, otherWay);
116 if (myWay.modified && !otherWay.modified)
117 return;
118 boolean same = true;
119 Iterator<LineSegment> it = otherWay.segments.iterator();
120 for (LineSegment ls : myWay.segments) {
121 if (!match(ls, it.next()))
122 same = false;
123 }
124 if (!same) {
125 myWay.segments.clear();
126 myWay.segments.addAll(otherWay.segments);
127 myWay.modified = otherWay.modified;
128 }
129 }
130 }
131
132 /**
133 * Postprocess the dataset and fix all merged references to point to the actual
134 * data.
135 */
136 public void fixReferences() {
137 for (LineSegment ls : ds.lineSegments) {
138 if (mergedNodes.containsKey(ls.from))
139 ls.from = mergedNodes.get(ls.from);
140 if (mergedNodes.containsKey(ls.to))
141 ls.to = mergedNodes.get(ls.to);
142 }
143 for (Way t : ds.ways) {
144 boolean replacedSomething = false;
145 LinkedList<LineSegment> newSegments = new LinkedList<LineSegment>();
146 for (LineSegment ls : t.segments) {
147 LineSegment otherLs = mergedLineSegments.get(ls);
148 newSegments.add(otherLs == null ? ls : otherLs);
149 if (otherLs != null)
150 replacedSomething = true;
151 }
152 if (replacedSomething) {
153 t.segments.clear();
154 t.segments.addAll(newSegments);
155 }
156 for (LineSegment ls : t.segments) {
157 if (mergedNodes.containsKey(ls.from))
158 ls.from = mergedNodes.get(ls.from);
159 if (mergedNodes.containsKey(ls.to))
160 ls.to = mergedNodes.get(ls.to);
161 }
162 }
163 }
164
165 /**
166 * @return Whether the nodes matches (in sense of "be mergable").
167 */
168 private boolean match(Node n1, Node n2) {
169 if (n1.id == 0 || n2.id == 0)
170 return n1.coor.equalsEpsilon(n2.coor);
171 return n1.id == n2.id;
172 }
173
174 /**
175 * @return Whether the line segments matches (in sense of "be mergable").
176 */
177 private boolean match(LineSegment ls1, LineSegment ls2) {
178 if (ls1.id == ls2.id)
179 return true;
180 if (ls1.incomplete || ls2.incomplete)
181 return false;
182 return match(ls1.from, ls2.from) && match(ls1.to, ls2.to);
183 }
184
185 /**
186 * @return Whether the ways matches (in sense of "be mergable").
187 */
188 private boolean match(Way t1, Way 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.