source: josm/trunk/src/org/openstreetmap/josm/data/osm/Relation.java@ 2308

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

fixed #3762: Deleted relation still referenced when deleting former member
Clean up of Delete command. New: only one confirmation dialog for all parent relations of deleted objects, see help.
Improved infrastructure for context-sensitive help, improved internal help browser.

  • Property svn:eol-style set to native
File size: 9.8 KB
Line 
1package org.openstreetmap.josm.data.osm;
2
3import java.util.ArrayList;
4import java.util.Collection;
5import java.util.HashMap;
6import java.util.HashSet;
7import java.util.List;
8import java.util.Map;
9import java.util.Set;
10
11import org.openstreetmap.josm.data.osm.visitor.Visitor;
12import org.openstreetmap.josm.tools.CopyList;
13
14/**
15 * An relation, having a set of tags and any number (0...n) of members.
16 *
17 * @author Frederik Ramm <frederik@remote.org>
18 */
19public final class Relation extends OsmPrimitive {
20
21 /**
22 * All members of this relation. Note that after changing this,
23 * makeBackReferences and/or removeBackReferences should be called.
24 *
25 */
26 private final List<RelationMember> members = new ArrayList<RelationMember>();
27
28 /**
29 * @return Members of the relation. Changes made in returned list are not mapped
30 * back to the primitive, use setMembers() to modify the members
31 * @since 1925
32 */
33 public List<RelationMember> getMembers() {
34 return new CopyList<RelationMember>(members.toArray(new RelationMember[members.size()]));
35 }
36
37 /**
38 *
39 * @param members Can be null, in that case all members are removed
40 * @since 1925
41 */
42 public void setMembers(List<RelationMember> members) {
43 this.members.clear();
44 if (members != null) {
45 this.members.addAll(members);
46 }
47 }
48
49 /**
50 *
51 * @since 1926
52 */
53 public int getMembersCount() {
54 return members.size();
55 }
56
57 /**
58 *
59 * @param index
60 * @return
61 * @since 1926
62 */
63 public RelationMember getMember(int index) {
64 return members.get(index);
65 }
66
67 /**
68 *
69 * @param member
70 * @since 1951
71 */
72 public void addMember(RelationMember member) {
73 members.add(member);
74 }
75
76 /**
77 *
78 * @param index
79 * @param member
80 * @since 1951
81 */
82 public void addMember(int index, RelationMember member) {
83 members.add(index, member);
84 }
85
86 /**
87 * Replace member at position specified by index.
88 * @param index
89 * @param member
90 * @return Member that was at the position
91 * @since 1951
92 */
93 public RelationMember setMember(int index, RelationMember member) {
94 return members.set(index, member);
95 }
96
97 /**
98 * Removes member at specified position.
99 * @param index
100 * @return Member that was at the position
101 * @since 1951
102 */
103 public RelationMember removeMember(int index) {
104 return members.remove(index);
105 }
106
107 @Override public void visit(Visitor visitor) {
108 visitor.visit(this);
109 }
110
111 protected Relation(long id, boolean allowNegative) {
112 super(id, allowNegative);
113 }
114
115 /**
116 * Create a new relation with id 0
117 */
118 public Relation() {
119 super(0, false);
120 }
121
122 /**
123 * Create an identical clone of the argument (including the id)
124 */
125 public Relation(Relation clone) {
126 super(clone.getUniqueId(), true);
127 cloneFrom(clone);
128 }
129
130 /**
131 * Creates a new relation for the given id. If the id > 0, the way is marked
132 * as incomplete.
133 *
134 * @param id the id. > 0 required
135 * @throws IllegalArgumentException thrown if id < 0
136 */
137 public Relation(long id) throws IllegalArgumentException {
138 super(id, false);
139 }
140
141 public Relation(RelationData data, DataSet dataSet) {
142 super(data);
143 load(data, dataSet);
144 }
145
146
147 @Override public void cloneFrom(OsmPrimitive osm) {
148 super.cloneFrom(osm);
149 members.clear();
150 // we must not add the members themselves, but instead
151 // add clones of the members
152 for (RelationMember em : ((Relation)osm).getMembers()) {
153 members.add(new RelationMember(em));
154 }
155 }
156
157 @Override public void load(PrimitiveData data, DataSet dataSet) {
158 super.load(data, dataSet);
159
160 RelationData relationData = (RelationData)data;
161
162 // TODO Make this faster
163
164 Node nodeMarker = new Node();
165 Way wayMarker = new Way();
166 Relation relationMarker = new Relation();
167 Map<Long, Node> nodes = new HashMap<Long, Node>();
168 Map<Long, Way> ways = new HashMap<Long, Way>();
169 Map<Long, Relation> relations = new HashMap<Long, Relation>();
170
171 for (RelationMemberData member:relationData.getMembers()) {
172 switch (member.getMemberType()) {
173 case NODE:
174 nodes.put(member.getMemberId(), nodeMarker);
175 break;
176 case WAY:
177 ways.put(member.getMemberId(), wayMarker);
178 break;
179 case RELATION:
180 relations.put(member.getMemberId(), relationMarker);
181 break;
182 }
183 }
184
185 for (Node node:dataSet.nodes) {
186 if (nodes.get(node.getUniqueId()) == nodeMarker) {
187 nodes.put(node.getUniqueId(), node);
188 }
189 }
190 for (Way way:dataSet.ways) {
191 if (ways.get(way.getUniqueId()) == wayMarker) {
192 ways.put(way.getUniqueId(), way);
193 }
194 }
195 for (Relation relation:dataSet.relations) {
196 if (relations.get(relation.getUniqueId()) == relationMarker) {
197 relations.put(relation.getUniqueId(), relation);
198 }
199 }
200
201 List<RelationMember> newMembers = new ArrayList<RelationMember>();
202 for (RelationMemberData member:relationData.getMembers()) {
203 OsmPrimitive foundMember = null;
204 switch (member.getMemberType()) {
205 case NODE:
206 foundMember = nodes.get(member.getMemberId());
207 if (foundMember == nodeMarker)
208 throw new AssertionError("Data consistency problem - relation with missing member detected");
209 break;
210 case WAY:
211 foundMember = ways.get(member.getMemberId());
212 if (foundMember == wayMarker)
213 throw new AssertionError("Data consistency problem - relation with missing member detected");
214 break;
215 case RELATION:
216 foundMember = relations.get(member.getMemberId());
217 if (foundMember == relationMarker)
218 throw new AssertionError("Data consistency problem - relation with missing member detected");
219 break;
220 }
221 newMembers.add(new RelationMember(member.getRole(), foundMember));
222 }
223 setMembers(newMembers);
224 }
225
226 @Override public RelationData save() {
227 RelationData data = new RelationData();
228 saveCommonAttributes(data);
229 for (RelationMember member:getMembers()) {
230 data.getMembers().add(new RelationMemberData(member.getRole(), member.getMember()));
231 }
232 return data;
233 }
234
235 @Override public String toString() {
236 // return "{Relation id="+id+" version="+version+" members="+Arrays.toString(members.toArray())+"}";
237 // adding members in string increases memory usage a lot and overflows for looped relations
238 return "{Relation id="+getId()+" version="+getVersion()+"}";
239 }
240
241 @Override
242 public boolean hasEqualSemanticAttributes(OsmPrimitive other) {
243 if (other == null || ! (other instanceof Relation) )
244 return false;
245 if (! super.hasEqualSemanticAttributes(other))
246 return false;
247 Relation r = (Relation)other;
248 return members.equals(r.members);
249 }
250
251 public int compareTo(OsmPrimitive o) {
252 return o instanceof Relation ? Long.valueOf(getId()).compareTo(o.getId()) : -1;
253 }
254
255 // seems to be different from member "incomplete" - FIXME
256 public boolean isIncomplete() {
257 for (RelationMember m : members)
258 if (m.getMember() == null)
259 return true;
260 return false;
261 }
262
263 public RelationMember firstMember() {
264 if (incomplete) return null;
265 return (members.size() == 0) ? null : members.get(0);
266 }
267 public RelationMember lastMember() {
268 if (incomplete) return null;
269 return (members.size() == 0) ? null : members.get(members.size() -1);
270 }
271
272 /**
273 * removes all members with member.member == primitive
274 *
275 * @param primitive the primitive to check for
276 */
277 public void removeMembersFor(OsmPrimitive primitive) {
278 if (primitive == null)
279 return;
280
281 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>();
282 for (RelationMember member: members) {
283 if (member.getMember() == primitive) {
284 todelete.add(member);
285 }
286 }
287 members.removeAll(todelete);
288 }
289
290 /**
291 * removes all members with member.member == primitive
292 *
293 * @param primitives the primitives to check for
294 */
295 public void removeMembersFor(Collection<OsmPrimitive> primitives) {
296 if (primitives == null || primitives.isEmpty())
297 return;
298
299 ArrayList<RelationMember> todelete = new ArrayList<RelationMember>();
300 for (RelationMember member: members) {
301 if (primitives.contains(member.getMember())) {
302 todelete.add(member);
303 }
304 }
305 members.removeAll(todelete);
306 }
307
308 @Override
309 public String getDisplayName(NameFormatter formatter) {
310 return formatter.format(this);
311 }
312
313 /**
314 * Replies the set of {@see OsmPrimitive}s referred to by at least one
315 * member of this relation
316 *
317 * @return the set of {@see OsmPrimitive}s referred to by at least one
318 * member of this relation
319 */
320 public Set<OsmPrimitive> getMemberPrimitives() {
321 HashSet<OsmPrimitive> ret = new HashSet<OsmPrimitive>();
322 for (RelationMember m: members) {
323 if (m.getMember() != null) {
324 ret.add(m.getMember());
325 }
326 }
327 return ret;
328 }
329}
Note: See TracBrowser for help on using the repository browser.