source: josm/src/org/openstreetmap/josm/data/osm/DataSet.java@ 23

Last change on this file since 23 was 23, checked in by imi, 18 years ago
  • added commands to support undo later
  • added Edit-Layer concept
  • painting of deleted objects
File size: 10.4 KB
Line 
1package org.openstreetmap.josm.data.osm;
2
3import java.util.Collection;
4import java.util.HashMap;
5import java.util.HashSet;
6import java.util.LinkedList;
7import java.util.Map;
8import java.util.Set;
9
10import org.openstreetmap.josm.data.Bounds;
11import org.openstreetmap.josm.data.SelectionTracker;
12import org.openstreetmap.josm.data.osm.visitor.AllNodesVisitor;
13
14/**
15 * DataSet is the data behind one window in the application. It can consist of only a few
16 * points up to the whole osm database. DataSet's can be merged together, split up into
17 * several different ones, saved, (up/down/disk)loaded etc.
18 *
19 * Note, that DataSet is not an osm-primitive, it is not within
20 * org.openstreetmap.josm.data.osm and has no key association but a few
21 * members to store some information.
22 *
23 * @author imi
24 */
25public class DataSet extends SelectionTracker implements Cloneable {
26
27 /**
28 * All nodes goes here, even when included in other data (tracks etc).
29 * This enables the instant conversion of the whole DataSet by iterating over
30 * this data structure.
31 */
32 public Collection<Node> nodes = new LinkedList<Node>();
33
34 /**
35 * All pending line segments goes here. Pending line segments are those, that
36 * are in this list but are in no track.
37 */
38 public Collection<LineSegment> pendingLineSegments = new LinkedList<LineSegment>();
39
40 /**
41 * All tracks (Streets etc.) in the DataSet.
42 *
43 * The nodes of the track segments of this track must be objects from
44 * the nodes list, however the track segments are stored only in the
45 * track list.
46 */
47 public Collection<Track> tracks = new LinkedList<Track>();
48
49
50 /**
51 * This is a list of all back references of nodes to their track usage.
52 */
53 public Map<Node, Set<Track>> nodeTrackRef = new HashMap<Node, Set<Track>>();
54 /**
55 * This is a list of all back references of nodes to their line segments.
56 */
57 public Map<Node, Set<LineSegment>> nodeLsRef = new HashMap<Node, Set<LineSegment>>();
58 /**
59 * This is a list of all back references of lines to their tracks.
60 */
61 public Map<LineSegment, Set<Track>> lsTrackRef = new HashMap<LineSegment, Set<Track>>();
62
63 /**
64 * Add a back reference from the node to the line segment.
65 */
66 public void addBackReference(Node from, LineSegment to) {
67 Set<LineSegment> references = nodeLsRef.get(from);
68 if (references == null)
69 references = new HashSet<LineSegment>();
70 references.add(to);
71 nodeLsRef.put(from, references);
72 }
73 /**
74 * Add a back reference from the node to the track.
75 */
76 public void addBackReference(Node from, Track to) {
77 Set<Track> references = nodeTrackRef.get(from);
78 if (references == null)
79 references = new HashSet<Track>();
80 references.add(to);
81 nodeTrackRef.put(from, references);
82 }
83 /**
84 * Add a back reference from the line segment to the track.
85 */
86 public void addBackReference(LineSegment from, Track to) {
87 Set<Track> references = lsTrackRef.get(from);
88 if (references == null)
89 references = new HashSet<Track>();
90 references.add(to);
91 lsTrackRef.put(from, references);
92 }
93
94 /**
95 * Removes all references to and from this line segment.
96 */
97 public void removeBackReference(LineSegment ls) {
98 Set<LineSegment> s = nodeLsRef.get(ls.start);
99 if (s != null)
100 s.remove(ls);
101 s = nodeLsRef.get(ls.end);
102 if (s != null)
103 s.remove(ls);
104 lsTrackRef.remove(ls);
105 }
106 /**
107 * Removes all references to and from the node.
108 */
109 public void removeBackReference(Node n) {
110 nodeLsRef.remove(n);
111 nodeTrackRef.remove(n);
112 }
113 /**
114 * Removes all references to and from the track.
115 */
116 public void removeBackReference(Track t) {
117 Collection<Node> nodes = AllNodesVisitor.getAllNodes(t);
118 for (Node n : nodes) {
119 Set<Track> s = nodeTrackRef.get(n);
120 if (s != null)
121 s.remove(t);
122 }
123 for (LineSegment ls : t.segments) {
124 Set<Track> s = lsTrackRef.get(ls);
125 if (s != null)
126 s.remove(t);
127 }
128 }
129
130 /**
131 * Rebuild the caches of back references.
132 */
133 public void rebuildBackReferences() {
134 nodeTrackRef.clear();
135 nodeLsRef.clear();
136 lsTrackRef.clear();
137 for (Track t : tracks) {
138 for (LineSegment ls : t.segments) {
139 addBackReference(ls.start, ls);
140 addBackReference(ls.end, ls);
141 addBackReference(ls.start, t);
142 addBackReference(ls.end, t);
143 addBackReference(ls, t);
144 }
145 }
146 for (LineSegment ls : pendingLineSegments) {
147 addBackReference(ls.start, ls);
148 addBackReference(ls.end, ls);
149 }
150 }
151
152 /**
153 * Return the bounds of this DataSet, depending on X/Y values.
154 * The min of the return value is the upper left GeoPoint, the max the lower
155 * down GeoPoint, regarding to the X/Y values.
156 *
157 * Return null, if any point not converted yet or if there are no points at all.
158 *
159 * @return Bounding coordinate structure.
160 */
161 public Bounds getBoundsXY() {
162 if (nodes.isEmpty())
163 return null;
164
165 Node first = nodes.iterator().next();
166 Bounds b = new Bounds(first.coor.clone(), first.coor.clone());
167 for (Node w : nodes)
168 {
169 if (Double.isNaN(w.coor.x) || Double.isNaN(w.coor.y))
170 return null;
171 if (w.coor.x < b.min.x)
172 b.min.x = w.coor.x;
173 if (w.coor.y < b.min.y)
174 b.min.y = w.coor.y;
175 if (w.coor.x > b.max.x)
176 b.max.x = w.coor.x;
177 if (w.coor.y > b.max.y)
178 b.max.y = w.coor.y;
179 }
180 return b;
181 }
182
183 /**
184 * Return the bounds of this DataSet, depending on lat/lon values.
185 * The min of the return value is the upper left GeoPoint, the max the lower
186 * down GeoPoint.
187 *
188 * Return null, if any point does not have lat/lon or if there are no
189 * points at all.
190 *
191 * @return Bounding coordinate structure.
192 */
193 public Bounds getBoundsLatLon() {
194 if (nodes.isEmpty())
195 return null;
196
197 Node first = nodes.iterator().next();
198 Bounds b = new Bounds(first.coor.clone(), first.coor.clone());
199 for (Node w : nodes)
200 {
201 if (Double.isNaN(w.coor.lat) || Double.isNaN(w.coor.lon))
202 return null;
203 if (w.coor.lat < b.min.lat)
204 b.min.lat = w.coor.lat;
205 if (w.coor.lon < b.min.lon)
206 b.min.lon = w.coor.lon;
207 if (w.coor.lat > b.max.lat)
208 b.max.lat = w.coor.lat;
209 if (w.coor.lon > b.max.lon)
210 b.max.lon = w.coor.lon;
211 }
212 return b;
213 }
214
215 /**
216 * Remove the selection of the whole dataset.
217 */
218 public void clearSelection() {
219 clearSelection(nodes);
220 clearSelection(tracks);
221 for (Track t : tracks)
222 clearSelection(t.segments);
223 }
224
225 /**
226 * Return a list of all selected objects. Even keys are returned.
227 * @return List of all selected objects.
228 */
229 @Override
230 public Collection<OsmPrimitive> getSelected() {
231 Collection<OsmPrimitive> sel = getSelected(nodes);
232 sel.addAll(getSelected(pendingLineSegments));
233 sel.addAll(getSelected(tracks));
234 for (Track t : tracks)
235 sel.addAll(getSelected(t.segments));
236 return sel;
237 }
238
239 /**
240 * Import the given dataset by merging all data with this dataset.
241 * The objects imported are not cloned, so from now on, these data belong
242 * to both datasets. So use mergeFrom only if you are about to abandon the
243 * other dataset.
244 *
245 * Elements are tried to merged.
246 * Nodes are merged first, if their lat/lon are equal.
247 * Line segments are merged, if they have the same nodes.
248 * Tracs are merged, if they consist of the same line segments.
249 *
250 * Additional to that, every two objects with the same id are merged.
251 *
252 * @param ds The DataSet to merge into this one.
253 * @return A list of all primitives that were used in the conjunction. That
254 * is all used primitives (the merged primitives and all added ones).
255 */
256 public Collection<OsmPrimitive> mergeFrom(DataSet ds) {
257 Collection<OsmPrimitive> data = new LinkedList<OsmPrimitive>();
258
259 Set<LineSegment> myLineSegments = new HashSet<LineSegment>();
260 myLineSegments.addAll(pendingLineSegments);
261 for (Track t : tracks)
262 myLineSegments.addAll(t.segments);
263
264 Set<LineSegment> otherLineSegments = new HashSet<LineSegment>();
265 otherLineSegments.addAll(ds.pendingLineSegments);
266 for (Track t : ds.tracks)
267 otherLineSegments.addAll(t.segments);
268
269
270 // merge nodes
271
272 Map<Node, Node> nodeMap = new HashMap<Node, Node>();
273 // find mergable
274 for (Node otherNode : ds.nodes)
275 for (Node myNode : nodes)
276 if (otherNode.coor.equalsLatLon(myNode.coor))
277 nodeMap.put(otherNode, myNode);
278 // add
279 data.addAll(new HashSet<Node>(nodeMap.values()));
280 for (Node n : ds.nodes) {
281 if (!nodeMap.containsKey(n)) {
282 nodes.add(n);
283 data.add(n);
284 }
285 }
286 // reassign
287 for (LineSegment ls : otherLineSegments) {
288 Node n = nodeMap.get(ls.start);
289 if (n != null)
290 ls.start = n;
291 n = nodeMap.get(ls.end);
292 if (n != null)
293 ls.end = n;
294 }
295
296
297 // merge line segments
298
299 Map<LineSegment, LineSegment> lsMap = new HashMap<LineSegment, LineSegment>();
300 // find mergable
301 for (LineSegment otherLS : otherLineSegments)
302 for (LineSegment myLS : myLineSegments)
303 if (otherLS.start == myLS.start && otherLS.end == myLS.end)
304 lsMap.put(otherLS, myLS);
305 // add pendings (ls from track are added later
306 for (LineSegment ls : ds.pendingLineSegments) {
307 if (!lsMap.containsKey(ls)) {
308 pendingLineSegments.add(ls);
309 data.add(ls);
310 }
311 }
312 // reassign
313 for (Track t : ds.tracks) {
314 for (int i = 0; i < t.segments.size(); ++i) {
315 LineSegment newLS = lsMap.get(t.segments.get(i));
316 if (newLS != null)
317 t.segments.set(i, newLS);
318 }
319 }
320
321
322 // merge tracks
323 LinkedList<Track> trackToAdd = new LinkedList<Track>();
324 for (Track otherTrack : ds.tracks) {
325 boolean found = false;
326 for (Track myTrack : tracks) {
327 if (myTrack.segments.equals(otherTrack.segments)) {
328 found = true;
329 data.add(myTrack);
330 break;
331 }
332 }
333 if (!found)
334 trackToAdd.add(otherTrack);
335 }
336 data.addAll(trackToAdd);
337 tracks.addAll(trackToAdd);
338
339 rebuildBackReferences();
340 return data;
341 }
342
343 /**
344 * Remove the selection from every value in the collection.
345 * @param list The collection to remove the selection from.
346 */
347 private void clearSelection(Collection<? extends OsmPrimitive> list) {
348 if (list == null)
349 return;
350 for (OsmPrimitive osm : list) {
351 osm.setSelected(false);
352 if (osm.keys != null)
353 clearSelection(osm.keys.keySet());
354 }
355 }
356
357 /**
358 * Return all selected items in the collection.
359 * @param list The collection from which the selected items are returned.
360 */
361 private Collection<OsmPrimitive> getSelected(Collection<? extends OsmPrimitive> list) {
362 Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
363 if (list == null)
364 return sel;
365 for (OsmPrimitive osm : list) {
366 if (osm.isSelected())
367 sel.add(osm);
368 if (osm.keys != null)
369 sel.addAll(getSelected(osm.keys.keySet()));
370 }
371 return sel;
372 }
373
374
375 @Override
376 public DataSet clone() {
377 try {return (DataSet)super.clone();} catch (CloneNotSupportedException e) {}
378 return null;
379 }
380}
Note: See TracBrowser for help on using the repository browser.