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

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

Added parameter Bounds to MapView, draw only currently visible primitives in MapPaintVisititor

  • Property svn:eol-style set to native
File size: 10.6 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 (incomplete) 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
136 @Override public void visit(Visitor visitor) {
137 visitor.visit(this);
138 }
139
140 protected Way(long id, boolean allowNegative) {
141 super(id, allowNegative);
142 }
143
144 /**
145 * Creates a new way with id 0.
146 *
147 */
148 public Way(){
149 super(0, false);
150 }
151
152 /**
153 *
154 * @param original
155 * @param clearId
156 */
157 public Way(Way original, boolean clearId) {
158 super(original.getUniqueId(), true);
159 cloneFrom(original);
160 if (clearId) {
161 clearOsmId();
162 }
163 }
164
165 /**
166 * Create an identical clone of the argument (including the id).
167 *
168 * @param original the original way. Must not be null.
169 */
170 public Way(Way original) {
171 this(original, false);
172 }
173
174 /**
175 * Creates a new way for the given id. If the id > 0, the way is marked
176 * as incomplete.
177 *
178 * @param id the id. > 0 required
179 * @throws IllegalArgumentException thrown if id < 0
180 */
181 public Way(long id) throws IllegalArgumentException {
182 super(id, false);
183 }
184
185 /**
186 *
187 * @param data
188 */
189 @Override
190 public void load(PrimitiveData data) {
191 super.load(data);
192
193 WayData wayData = (WayData) data;
194
195 List<Node> newNodes = new ArrayList<Node>(wayData.getNodes().size());
196 for (Long nodeId : wayData.getNodes()) {
197 Node node = (Node)getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE);
198 if (node != null) {
199 newNodes.add(node);
200 } else
201 throw new AssertionError("Data consistency problem - way with missing node detected");
202 }
203 setNodes(newNodes);
204 }
205
206 @Override public WayData save() {
207 WayData data = new WayData();
208 saveCommonAttributes(data);
209 for (Node node:getNodes()) {
210 data.getNodes().add(node.getUniqueId());
211 }
212 return data;
213 }
214
215 @Override public void cloneFrom(OsmPrimitive osm) {
216 super.cloneFrom(osm);
217 Way otherWay = (Way)osm;
218 setNodes(otherWay.getNodes());
219 }
220
221 @Override public String toString() {
222 String nodesDesc = incomplete?"(incomplete)":"nodes=" + Arrays.toString(nodes);
223 return "{Way id=" + getUniqueId() + " version=" + getVersion()+ " " + getFlagsAsString() + " " + nodesDesc + "}";
224 }
225
226 @Override
227 public boolean hasEqualSemanticAttributes(OsmPrimitive other) {
228 if (other == null || ! (other instanceof Way) )
229 return false;
230 if (! super.hasEqualSemanticAttributes(other))
231 return false;
232 Way w = (Way)other;
233 if (getNodesCount() != w.getNodesCount()) return false;
234 for (int i=0;i<getNodesCount();i++) {
235 if (! getNode(i).hasEqualSemanticAttributes(w.getNode(i)))
236 return false;
237 }
238 return true;
239 }
240
241 public int compareTo(OsmPrimitive o) {
242 if (o instanceof Relation)
243 return 1;
244 return o instanceof Way ? Long.valueOf(getId()).compareTo(o.getId()) : -1;
245 }
246
247 public void removeNode(Node n) {
248 if (incomplete) return;
249 boolean closed = (lastNode() == n && firstNode() == n);
250 int i;
251 List<Node> copy = getNodes();
252 while ((i = copy.indexOf(n)) >= 0) {
253 copy.remove(i);
254 }
255 i = copy.size();
256 if (closed && i > 2) {
257 // TODO Should this be copy.addNode(firstNode)?
258 addNode(firstNode());
259 } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
260 copy.remove(i-1);
261 }
262 setNodes(copy);
263 }
264
265 public void removeNodes(Collection<? extends OsmPrimitive> selection) {
266 if (incomplete) return;
267 for(OsmPrimitive p : selection) {
268 if (p instanceof Node) {
269 removeNode((Node)p);
270 }
271 }
272 }
273
274 /**
275 * Adds a node to the end of the list of nodes. Ignored, if n is null.
276 *
277 * @param n the node. Ignored, if null.
278 * @throws IllegalStateException thrown, if this way is marked as incomplete. We can't add a node
279 * to an incomplete way
280 */
281 public void addNode(Node n) throws IllegalStateException {
282 if (n==null) return;
283 if (incomplete)
284 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
285 clearCached();
286 n.addReferrer(this);
287 Node[] newNodes = new Node[nodes.length + 1];
288 System.arraycopy(nodes, 0, newNodes, 0, nodes.length);
289 newNodes[nodes.length] = n;
290 nodes = newNodes;
291 fireNodesChanged();
292 }
293
294 /**
295 * Adds a node at position offs.
296 *
297 * @param int offs the offset
298 * @param n the node. Ignored, if null.
299 * @throws IllegalStateException thrown, if this way is marked as incomplete. We can't add a node
300 * to an incomplete way
301 * @throws IndexOutOfBoundsException thrown if offs is out of bounds
302 */
303 public void addNode(int offs, Node n) throws IllegalStateException, IndexOutOfBoundsException {
304 if (n==null) return;
305 if (incomplete)
306 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
307 clearCached();
308 n.addReferrer(this);
309 Node[] newNodes = new Node[nodes.length + 1];
310 System.arraycopy(nodes, 0, newNodes, 0, offs);
311 System.arraycopy(nodes, offs, newNodes, offs + 1, nodes.length - offs);
312 newNodes[offs] = n;
313 nodes = newNodes;
314 fireNodesChanged();
315 }
316
317 @Override
318 public void setDeleted(boolean deleted) {
319 for (Node n:nodes) {
320 if (deleted) {
321 n.removeReferrer(this);
322 } else {
323 n.addReferrer(this);
324 }
325 }
326 fireNodesChanged();
327 super.setDeleted(deleted);
328 }
329
330
331 public boolean isClosed() {
332 if (incomplete) return false;
333 return nodes.length >= 3 && lastNode() == firstNode();
334 }
335
336 public Node lastNode() {
337 if (incomplete || nodes.length == 0) return null;
338 return nodes[nodes.length-1];
339 }
340
341 public Node firstNode() {
342 if (incomplete || nodes.length == 0) return null;
343 return nodes[0];
344 }
345
346 public boolean isFirstLastNode(Node n) {
347 if (incomplete || nodes.length == 0) return false;
348 return n == firstNode() || n == lastNode();
349 }
350
351 @Override
352 public String getDisplayName(NameFormatter formatter) {
353 return formatter.format(this);
354 }
355
356 public OsmPrimitiveType getType() {
357 return OsmPrimitiveType.WAY;
358 }
359
360 private void fireNodesChanged() {
361 if (getDataSet() != null) {
362 getDataSet().fireWayNodesChanged(this);
363 }
364 }
365
366 @Override
367 public BBox getBBox() {
368 if (getDataSet() == null)
369 return new BBox(this);
370 if (bbox == null) {
371 bbox = new BBox(this);
372 }
373 return bbox;
374 }
375
376 @Override
377 public void updatePosition() {
378 bbox = new BBox(this);
379 }
380}
Note: See TracBrowser for help on using the repository browser.