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

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

Change most occurrences of Dataset.nodes/ways/relations with getNodes()/../.. or addPrimitive

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