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

Last change on this file since 2077 was 2077, checked in by Gubaer, 15 years ago

Had to replace DataSet:getPrimitiveById(id) with DataSet:getPrimitiveById(id,type). Primitive ids are not globally unique, only per type of primitive.
Fixed problems in unit test, available unit tests passing again.

  • Property svn:eol-style set to native
File size: 15.5 KB
Line 
1// License: GPL. Copyright 2007 by Immanuel Scholz and others
2package org.openstreetmap.josm.data.osm;
3
4import static org.openstreetmap.josm.tools.I18n.tr;
5
6import java.awt.geom.Area;
7import java.util.ArrayList;
8import java.util.Arrays;
9import java.util.Collection;
10import java.util.Comparator;
11import java.util.HashMap;
12import java.util.HashSet;
13import java.util.Iterator;
14import java.util.LinkedList;
15import java.util.List;
16import java.util.Set;
17
18import org.openstreetmap.josm.data.SelectionChangedListener;
19
20/**
21 * DataSet is the data behind the application. It can consists of only a few points up to the whole
22 * osm database. DataSet's can be merged together, saved, (up/down/disk)loaded etc.
23 *
24 * Note that DataSet is not an osm-primitive and so has no key association but a few members to
25 * store some information.
26 *
27 * @author imi
28 */
29public class DataSet implements Cloneable {
30
31 /**
32 * The API version that created this data set, if any.
33 */
34 public String version;
35
36 /**
37 * All nodes goes here, even when included in other data (ways etc). This enables the instant
38 * conversion of the whole DataSet by iterating over this data structure.
39 */
40 public Collection<Node> nodes = new LinkedList<Node>();
41
42 /**
43 * All ways (Streets etc.) in the DataSet.
44 *
45 * The way nodes are stored only in the way list.
46 */
47 public Collection<Way> ways = new LinkedList<Way>();
48
49 /**
50 * All relations/relationships
51 */
52 public Collection<Relation> relations = new LinkedList<Relation>();
53
54 /**
55 * All data sources of this DataSet.
56 */
57 public Collection<DataSource> dataSources = new LinkedList<DataSource>();
58
59 /**
60 * A list of listeners to selection changed events. The list is static, as listeners register
61 * themselves for any dataset selection changes that occur, regardless of the current active
62 * dataset. (However, the selection does only change in the active layer)
63 */
64 public static Collection<SelectionChangedListener> selListeners = new LinkedList<SelectionChangedListener>();
65
66 /**
67 * @return A collection containing all primitives of the dataset. The data is ordered after:
68 * first come nodes, then ways, then relations. Ordering in between the categories is not
69 * guaranteed.
70 */
71 public List<OsmPrimitive> allPrimitives() {
72 List<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
73 o.addAll(nodes);
74 o.addAll(ways);
75 o.addAll(relations);
76 return o;
77 }
78
79 /**
80 * @return A collection containing all not-deleted primitives (except keys).
81 */
82 public Collection<OsmPrimitive> allNonDeletedPrimitives() {
83 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
84 for (OsmPrimitive osm : allPrimitives())
85 if (osm.isVisible() && !osm.isDeleted()) {
86 o.add(osm);
87 }
88 return o;
89 }
90
91 public Collection<OsmPrimitive> allNonDeletedCompletePrimitives() {
92 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
93 for (OsmPrimitive osm : allPrimitives())
94 if (osm.isVisible() && !osm.isDeleted() && !osm.incomplete) {
95 o.add(osm);
96 }
97 return o;
98 }
99
100 public Collection<OsmPrimitive> allNonDeletedPhysicalPrimitives() {
101 Collection<OsmPrimitive> o = new LinkedList<OsmPrimitive>();
102 for (OsmPrimitive osm : allPrimitives())
103 if (osm.isVisible() && !osm.isDeleted() && !osm.incomplete && !(osm instanceof Relation)) {
104 o.add(osm);
105 }
106 return o;
107 }
108
109 /**
110 * Adds a primitive to the dataset
111 *
112 * @param primitive the primitive. Ignored if null.
113 */
114 public void addPrimitive(OsmPrimitive primitive) {
115 if (primitive == null)
116 return;
117 if (primitive instanceof Node) {
118 nodes.add((Node) primitive);
119 } else if (primitive instanceof Way) {
120 ways.add((Way) primitive);
121 } else if (primitive instanceof Relation) {
122 relations.add((Relation) primitive);
123 }
124 }
125
126 /**
127 * Removes a primitive from the dataset. This method only removes the
128 * primitive form the respective collection of primitives managed
129 * by this dataset, i.e. from {@see #nodes}, {@see #ways}, or
130 * {@see #relations}. References from other primitives to this
131 * primitive are left unchanged.
132 *
133 * @param primitive the primitive. Ignored if null.
134 */
135 public void removePrimitive(OsmPrimitive primitive) {
136 if (primitive == null)
137 return;
138 if (primitive instanceof Node) {
139 nodes.remove(primitive);
140 } else if (primitive instanceof Way) {
141 ways.remove(primitive);
142 } else if (primitive instanceof Relation) {
143 relations.remove(primitive);
144 }
145 }
146
147 public Collection<OsmPrimitive> getSelectedNodesAndWays() {
148 Collection<OsmPrimitive> sel = getSelected(nodes);
149 sel.addAll(getSelected(ways));
150 return sel;
151 }
152
153
154 /**
155 * Return a list of all selected objects. Even keys are returned.
156 * @return List of all selected objects.
157 */
158 public Collection<OsmPrimitive> getSelected() {
159 Collection<OsmPrimitive> sel = getSelected(nodes);
160 sel.addAll(getSelected(ways));
161 sel.addAll(getSelected(relations));
162 return sel;
163 }
164
165 /**
166 * Return selected nodes.
167 */
168 public Collection<OsmPrimitive> getSelectedNodes() {
169 return getSelected(nodes);
170 }
171
172 /**
173 * Return selected ways.
174 */
175 public Collection<OsmPrimitive> getSelectedWays() {
176 return getSelected(ways);
177 }
178
179 /**
180 * Return selected relations.
181 */
182 public Collection<OsmPrimitive> getSelectedRelations() {
183 return getSelected(relations);
184 }
185
186 public void setSelected(Collection<? extends OsmPrimitive> selection) {
187 clearSelection(nodes);
188 clearSelection(ways);
189 clearSelection(relations);
190 for (OsmPrimitive osm : selection) {
191 osm.setSelected(true);
192 }
193 fireSelectionChanged(selection);
194 }
195
196 public void setSelected(OsmPrimitive... osm) {
197 if (osm.length == 1 && osm[0] == null) {
198 setSelected();
199 return;
200 }
201 clearSelection(nodes);
202 clearSelection(ways);
203 clearSelection(relations);
204 for (OsmPrimitive o : osm)
205 if (o != null) {
206 o.setSelected(true);
207 }
208 fireSelectionChanged(Arrays.asList(osm));
209 }
210
211 /**
212 * Remove the selection from every value in the collection.
213 * @param list The collection to remove the selection from.
214 */
215 private void clearSelection(Collection<? extends OsmPrimitive> list) {
216 if (list == null)
217 return;
218 for (OsmPrimitive osm : list) {
219 osm.setSelected(false);
220 }
221 }
222
223 /**
224 * Return all selected items in the collection.
225 * @param list The collection from which the selected items are returned.
226 */
227 private Collection<OsmPrimitive> getSelected(Collection<? extends OsmPrimitive> list) {
228 Collection<OsmPrimitive> sel = new HashSet<OsmPrimitive>();
229 if (list == null)
230 return sel;
231 for (OsmPrimitive osm : list)
232 if (osm.isSelected() && !osm.isDeleted()) {
233 sel.add(osm);
234 }
235 return sel;
236 }
237
238 /**
239 * Remember to fire an selection changed event. A call to this will not fire the event
240 * immediately. For more,
241 * @see SelectionChangedListener
242 */
243 public static void fireSelectionChanged(Collection<? extends OsmPrimitive> sel) {
244 for (SelectionChangedListener l : selListeners) {
245 l.selectionChanged(sel);
246 }
247 }
248
249 @Override public DataSet clone() {
250 DataSet ds = new DataSet();
251 for (Node n : nodes) {
252 ds.nodes.add(new Node(n));
253 }
254 for (Way w : ways) {
255 ds.ways.add(new Way(w));
256 }
257 for (Relation e : relations) {
258 ds.relations.add(new Relation(e));
259 }
260 for (DataSource source : dataSources) {
261 ds.dataSources.add(new DataSource(source.bounds, source.origin));
262 }
263 ds.version = version;
264 return ds;
265 }
266
267 /**
268 * Returns the total area of downloaded data (the "yellow rectangles").
269 * @return Area object encompassing downloaded data.
270 */
271 public Area getDataSourceArea() {
272 if (dataSources.isEmpty()) return null;
273 Area a = new Area();
274 for (DataSource source : dataSources) {
275 // create area from data bounds
276 a.add(new Area(source.bounds.asRect()));
277 }
278 return a;
279 }
280
281 // Provide well-defined sorting for collections of OsmPrimitives.
282 // FIXME: probably not a good place to put this code.
283 public static OsmPrimitive[] sort(Collection<? extends OsmPrimitive> list) {
284 OsmPrimitive[] selArr = new OsmPrimitive[list.size()];
285 final HashMap<Object, String> h = new HashMap<Object, String>();
286 selArr = list.toArray(selArr);
287 Arrays.sort(selArr, new Comparator<OsmPrimitive>() {
288 public int compare(OsmPrimitive a, OsmPrimitive b) {
289 if (a.getClass() == b.getClass()) {
290 String as = h.get(a);
291 if (as == null) {
292 as = a.getName() != null ? a.getName() : Long.toString(a.getId());
293 h.put(a, as);
294 }
295 String bs = h.get(b);
296 if (bs == null) {
297 bs = b.getName() != null ? b.getName() : Long.toString(b.getId());
298 h.put(b, bs);
299 }
300 int res = as.compareTo(bs);
301 if (res != 0)
302 return res;
303 }
304 return a.compareTo(b);
305 }
306 });
307 return selArr;
308 }
309
310 /**
311 * returns a primitive with a given id from the data set. null, if no such primitive
312 * exists
313 *
314 * @param id the id, > 0 required
315 * @param type the type of the primitive. Must not be null.
316 * @return the primitive
317 * @exception IllegalArgumentException thrown, if id <= 0
318 * @exception IllegalArgumentException thrown, if type is null
319 * @exception IllegalArgumentException thrown, if type is neither NODE, or WAY or RELATION
320 */
321 public OsmPrimitive getPrimitiveById(long id, OsmPrimitiveType type) {
322 if (id <= 0)
323 throw new IllegalArgumentException(tr("parameter {0} > 0 required. Got {1}.", "id", id));
324 if (id <= 0)
325 throw new IllegalArgumentException(tr("paramete''{0}'' must not be null", "type"));
326 Collection<? extends OsmPrimitive> primitives = null;
327 switch(type) {
328 case NODE: primitives = nodes; break;
329 case WAY: primitives = ways; break;
330 case RELATION: primitives = relations; break;
331 case CHANGESET: throw new IllegalArgumentException(tr("unsupported value ''{0}'' or parameter ''{1}''", type, "type"));
332 }
333 for (OsmPrimitive primitive : primitives) {
334 if (primitive.getId() == id) return primitive;
335 }
336 return null;
337 }
338
339 public Set<Long> getPrimitiveIds() {
340 HashSet<Long> ret = new HashSet<Long>();
341 for (OsmPrimitive primitive : nodes) {
342 ret.add(primitive.getId());
343 }
344 for (OsmPrimitive primitive : ways) {
345 ret.add(primitive.getId());
346 }
347 for (OsmPrimitive primitive : relations) {
348 ret.add(primitive.getId());
349 }
350 return ret;
351 }
352
353 protected void deleteWay(Way way) {
354 way.setNodes(null);
355 way.setDeleted(true);
356 }
357
358 /**
359 * removes all references from ways in this dataset to a particular node
360 *
361 * @param node the node
362 */
363 public void unlinkNodeFromWays(Node node) {
364 for (Way way: ways) {
365 List<Node> nodes = way.getNodes();
366 if (nodes.remove(node)) {
367 if (nodes.size() < 2) {
368 deleteWay(way);
369 } else {
370 way.setNodes(nodes);
371 }
372 }
373 }
374 }
375
376 /**
377 * removes all references from relations in this dataset to this primitive
378 *
379 * @param primitive the primitive
380 */
381 public void unlinkPrimitiveFromRelations(OsmPrimitive primitive) {
382 for (Relation relation : relations) {
383 Iterator<RelationMember> it = relation.getMembers().iterator();
384 while(it.hasNext()) {
385 RelationMember member = it.next();
386 if (member.getMember().equals(primitive)) {
387 it.remove();
388 }
389 }
390 }
391 }
392
393 /**
394 * removes all references from from other primitives to the
395 * referenced primitive
396 *
397 * @param referencedPrimitive the referenced primitive
398 */
399 public void unlinkReferencesToPrimitive(OsmPrimitive referencedPrimitive) {
400 if (referencedPrimitive instanceof Node) {
401 unlinkNodeFromWays((Node)referencedPrimitive);
402 unlinkPrimitiveFromRelations(referencedPrimitive);
403 } else {
404 unlinkPrimitiveFromRelations(referencedPrimitive);
405 }
406 }
407
408 /**
409 * Replies a list of parent relations which refer to the relation
410 * <code>child</code>. Replies an empty list if child is null.
411 *
412 * @param child the child relation
413 * @return a list of parent relations which refer to the relation
414 * <code>child</code>
415 */
416 public List<Relation> getParentRelations(Relation child) {
417 ArrayList<Relation> parents = new ArrayList<Relation>();
418 if (child == null)
419 return parents;
420 for (Relation parent : relations) {
421 if (parent == child) {
422 continue;
423 }
424 for (RelationMember member: parent.getMembers()) {
425 if (member.refersTo(child)) {
426 parents.add(parent);
427 break;
428 }
429 }
430 }
431 return parents;
432 }
433
434 /**
435 * Replies true if there is at least one primitive in this dataset with
436 * {@see OsmPrimitive#isModified()} == <code>true</code>.
437 *
438 * @return true if there is at least one primitive in this dataset with
439 * {@see OsmPrimitive#isModified()} == <code>true</code>.
440 */
441 public boolean isModified() {
442 for (Node n: nodes) {
443 if (n.isModified()) return true;
444 }
445 for (Way w: ways) {
446 if (w.isModified()) return true;
447 }
448 for (Relation r: relations) {
449 if (r.isModified()) return true;
450 }
451 return false;
452 }
453
454 public Set<Relation> getReferringRelations(Collection<? extends OsmPrimitive> primitives) {
455 HashSet<Relation> ret = new HashSet<Relation>();
456 if (primitives == null) return ret;
457 Set<? extends OsmPrimitive> referred;
458 if (primitives instanceof Set<?>) {
459 referred = (Set<? extends OsmPrimitive>)primitives;
460 } else {
461 referred = new HashSet<OsmPrimitive>(primitives);
462 }
463 referred.remove(null); // just in case - remove null element from primitives
464 for (Relation r: relations) {
465 if (r.isDeleted() || r.incomplete) {
466 continue;
467 }
468 Set<OsmPrimitive> memberPrimitives = r.getMemberPrimitives();
469 memberPrimitives.retainAll(referred);
470 if (!memberPrimitives.isEmpty()) {
471 ret.add(r);
472 }
473 }
474 return ret;
475 }
476}
Note: See TracBrowser for help on using the repository browser.