source: josm/trunk/src/org/openstreetmap/josm/data/osm/Way.java@ 2656

Last change on this file since 2656 was 2620, checked in by jttt, 14 years ago

Remove OsmPrimitive.setIncomplete()

  • Property svn:eol-style set to native
File size: 11.2 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.util.ArrayList;
7import java.util.Arrays;
8import java.util.Collection;
9import java.util.List;
10
11import org.openstreetmap.josm.data.osm.visitor.Visitor;
12import org.openstreetmap.josm.tools.CopyList;
13import org.openstreetmap.josm.tools.Pair;
14
15/**
16 * One full way, consisting of a list of way nodes.
17 *
18 * @author imi
19 */
20public final class Way extends OsmPrimitive {
21
22 /**
23 * All way nodes in this way
24 *
25 */
26 private Node[] nodes = new Node[0];
27 private BBox bbox;
28
29 /**
30 *
31 * You can modify returned list but changes will not be propagated back
32 * to the Way. Use {@link #setNodes(List)} to update this way
33 * @return Nodes composing the way
34 * @since 1862
35 */
36 public List<Node> getNodes() {
37 return new CopyList<Node>(nodes);
38 }
39
40 /**
41 * Set new list of nodes to way. This method is preferred to multiple calls to addNode/removeNode
42 * and similar methods because nodes are internally saved as array which means lower memory overhead
43 * but also slower modifying operations.
44 * @param nodes New way nodes. Can be null, in that case all way nodes are removed
45 * @since 1862
46 */
47 public void setNodes(List<Node> nodes) {
48 for (Node node:this.nodes) {
49 node.removeReferrer(this);
50 }
51
52 if (nodes == null) {
53 this.nodes = new Node[0];
54 } else {
55 this.nodes = nodes.toArray(new Node[nodes.size()]);
56 }
57 for (Node node:this.nodes) {
58 node.addReferrer(this);
59 }
60
61 clearCached();
62 fireNodesChanged();
63 }
64
65 /**
66 * Replies the number of nodes in this ways.
67 *
68 * @return the number of nodes in this ways.
69 * @since 1862
70 */
71 public int getNodesCount() {
72 return nodes.length;
73 }
74
75 /**
76 * Replies the node at position <code>index</code>.
77 *
78 * @param index the position
79 * @return the node at position <code>index</code>
80 * @exception IndexOutOfBoundsException thrown if <code>index</code> < 0
81 * or <code>index</code> >= {@see #getNodesCount()}
82 * @since 1862
83 */
84 public Node getNode(int index) {
85 return nodes[index];
86 }
87
88 /**
89 * Replies true if this way contains the node <code>node</code>, false
90 * otherwise. Replies false if <code>node</code> is null.
91 *
92 * @param node the node. May be null.
93 * @return true if this way contains the node <code>node</code>, false
94 * otherwise
95 * @since 1909
96 */
97 public boolean containsNode(Node node) {
98 if (node == null) return false;
99 for (int i=0; i<nodes.length; i++) {
100 if (nodes[i].equals(node))
101 return true;
102 }
103 return false;
104 }
105
106 /* mappaint data */
107 public boolean isMappaintArea = false;
108 public Integer mappaintDrawnAreaCode = 0;
109 /* end of mappaint data */
110 @Override protected void clearCached() {
111 super.clearCached();
112 isMappaintArea = false;
113 mappaintDrawnAreaCode = 0;
114 }
115
116 public ArrayList<Pair<Node,Node>> getNodePairs(boolean sort) {
117 ArrayList<Pair<Node,Node>> chunkSet = new ArrayList<Pair<Node,Node>>();
118 if (isIncomplete()) return chunkSet;
119 Node lastN = null;
120 for (Node n : this.nodes) {
121 if (lastN == null) {
122 lastN = n;
123 continue;
124 }
125 Pair<Node,Node> np = new Pair<Node,Node>(lastN, n);
126 if (sort) {
127 Pair.sort(np);
128 }
129 chunkSet.add(np);
130 lastN = n;
131 }
132 return chunkSet;
133 }
134
135 @Override public void visit(Visitor visitor) {
136 visitor.visit(this);
137 }
138
139 protected Way(long id, boolean allowNegative) {
140 super(id, allowNegative);
141 }
142
143 /**
144 * Creates a new way with id 0.
145 *
146 */
147 public Way(){
148 super(0, false);
149 }
150
151 /**
152 *
153 * @param original
154 * @param clearId
155 */
156 public Way(Way original, boolean clearId) {
157 super(original.getUniqueId(), true);
158 cloneFrom(original);
159 if (clearId) {
160 clearOsmId();
161 }
162 }
163
164 /**
165 * Create an identical clone of the argument (including the id).
166 *
167 * @param original the original way. Must not be null.
168 */
169 public Way(Way original) {
170 this(original, false);
171 }
172
173 /**
174 * Creates a new way for the given id. If the id > 0, the way is marked
175 * as incomplete. If id == 0 then way is marked as new
176 *
177 * @param id the id. >= 0 required
178 * @throws IllegalArgumentException thrown if id < 0
179 */
180 public Way(long id) throws IllegalArgumentException {
181 super(id, false);
182 }
183
184 /**
185 * Creates new way with given id and version. Way is marked as complete
186 * @param id
187 * @param version
188 */
189 public Way(long id, int version) {
190 super(id, false);
191 setOsmId(id, version);
192 }
193
194 /**
195 *
196 * @param data
197 */
198 @Override
199 public void load(PrimitiveData data) {
200 super.load(data);
201
202 WayData wayData = (WayData) data;
203
204 List<Node> newNodes = new ArrayList<Node>(wayData.getNodes().size());
205 for (Long nodeId : wayData.getNodes()) {
206 Node node = (Node)getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE);
207 if (node != null) {
208 newNodes.add(node);
209 } else
210 throw new AssertionError("Data consistency problem - way with missing node detected");
211 }
212 setNodes(newNodes);
213 }
214
215 @Override public WayData save() {
216 WayData data = new WayData();
217 saveCommonAttributes(data);
218 for (Node node:getNodes()) {
219 data.getNodes().add(node.getUniqueId());
220 }
221 return data;
222 }
223
224 @Override public void cloneFrom(OsmPrimitive osm) {
225 super.cloneFrom(osm);
226 Way otherWay = (Way)osm;
227 setNodes(otherWay.getNodes());
228 }
229
230 @Override public String toString() {
231 String nodesDesc = isIncomplete()?"(incomplete)":"nodes=" + Arrays.toString(nodes);
232 return "{Way id=" + getUniqueId() + " version=" + getVersion()+ " " + getFlagsAsString() + " " + nodesDesc + "}";
233 }
234
235 @Override
236 public boolean hasEqualSemanticAttributes(OsmPrimitive other) {
237 if (other == null || ! (other instanceof Way) )
238 return false;
239 if (! super.hasEqualSemanticAttributes(other))
240 return false;
241 Way w = (Way)other;
242 if (getNodesCount() != w.getNodesCount()) return false;
243 for (int i=0;i<getNodesCount();i++) {
244 if (! getNode(i).hasEqualSemanticAttributes(w.getNode(i)))
245 return false;
246 }
247 return true;
248 }
249
250 public int compareTo(OsmPrimitive o) {
251 if (o instanceof Relation)
252 return 1;
253 return o instanceof Way ? Long.valueOf(getUniqueId()).compareTo(o.getUniqueId()) : -1;
254 }
255
256 public void removeNode(Node n) {
257 if (isIncomplete()) return;
258 boolean closed = (lastNode() == n && firstNode() == n);
259 int i;
260 List<Node> copy = getNodes();
261 while ((i = copy.indexOf(n)) >= 0) {
262 copy.remove(i);
263 }
264 i = copy.size();
265 if (closed && i > 2) {
266 copy.add(copy.get(0));
267 } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
268 copy.remove(i-1);
269 }
270 setNodes(copy);
271 }
272
273 public void removeNodes(Collection<? extends OsmPrimitive> selection) {
274 if (isIncomplete()) return;
275 for(OsmPrimitive p : selection) {
276 if (p instanceof Node) {
277 removeNode((Node)p);
278 }
279 }
280 }
281
282 /**
283 * Adds a node to the end of the list of nodes. Ignored, if n is null.
284 *
285 * @param n the node. Ignored, if null.
286 * @throws IllegalStateException thrown, if this way is marked as incomplete. We can't add a node
287 * to an incomplete way
288 */
289 public void addNode(Node n) throws IllegalStateException {
290 if (n==null) return;
291 if (isIncomplete())
292 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
293 clearCached();
294 n.addReferrer(this);
295 Node[] newNodes = new Node[nodes.length + 1];
296 System.arraycopy(nodes, 0, newNodes, 0, nodes.length);
297 newNodes[nodes.length] = n;
298 nodes = newNodes;
299 fireNodesChanged();
300 }
301
302 /**
303 * Adds a node at position offs.
304 *
305 * @param int offs the offset
306 * @param n the node. Ignored, if null.
307 * @throws IllegalStateException thrown, if this way is marked as incomplete. We can't add a node
308 * to an incomplete way
309 * @throws IndexOutOfBoundsException thrown if offs is out of bounds
310 */
311 public void addNode(int offs, Node n) throws IllegalStateException, IndexOutOfBoundsException {
312 if (n==null) return;
313 if (isIncomplete())
314 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
315 clearCached();
316 n.addReferrer(this);
317 Node[] newNodes = new Node[nodes.length + 1];
318 System.arraycopy(nodes, 0, newNodes, 0, offs);
319 System.arraycopy(nodes, offs, newNodes, offs + 1, nodes.length - offs);
320 newNodes[offs] = n;
321 nodes = newNodes;
322 fireNodesChanged();
323 }
324
325 @Override
326 public void setDeleted(boolean deleted) {
327 for (Node n:nodes) {
328 if (deleted) {
329 n.removeReferrer(this);
330 } else {
331 n.addReferrer(this);
332 }
333 }
334 fireNodesChanged();
335 super.setDeleted(deleted);
336 }
337
338 public boolean isClosed() {
339 if (isIncomplete()) return false;
340 return nodes.length >= 3 && lastNode() == firstNode();
341 }
342
343 public Node lastNode() {
344 if (isIncomplete() || nodes.length == 0) return null;
345 return nodes[nodes.length-1];
346 }
347
348 public Node firstNode() {
349 if (isIncomplete() || nodes.length == 0) return null;
350 return nodes[0];
351 }
352
353 public boolean isFirstLastNode(Node n) {
354 if (isIncomplete() || nodes.length == 0) return false;
355 return n == firstNode() || n == lastNode();
356 }
357
358 @Override
359 public String getDisplayName(NameFormatter formatter) {
360 return formatter.format(this);
361 }
362
363 public OsmPrimitiveType getType() {
364 return OsmPrimitiveType.WAY;
365 }
366
367 private void fireNodesChanged() {
368 if (getDataSet() != null) {
369 getDataSet().fireWayNodesChanged(this);
370 }
371 }
372
373 @Override
374 public BBox getBBox() {
375 if (getDataSet() == null)
376 return new BBox(this);
377 if (bbox == null) {
378 bbox = new BBox(this);
379 }
380 return bbox;
381 }
382
383 @Override
384 public void updatePosition() {
385 bbox = new BBox(this);
386 }
387
388 public boolean hasIncompleteNodes() {
389 for (Node node:getNodes()) {
390 if (node.isIncomplete())
391 return true;
392 }
393 return false;
394 }
395
396 @Override
397 public boolean isUsable() {
398 return super.isUsable() && !hasIncompleteNodes();
399 }
400}
Note: See TracBrowser for help on using the repository browser.