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

Last change on this file since 13434 was 13434, checked in by Don-vip, 7 years ago

see #8039, see #10456 - support read-only data layers

  • Property svn:eol-style set to native
File size: 24.8 KB
Line 
1// License: GPL. For details, see LICENSE file.
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.HashSet;
9import java.util.List;
10import java.util.Map;
11import java.util.Set;
12
13import org.openstreetmap.josm.data.coor.LatLon;
14import org.openstreetmap.josm.data.osm.visitor.OsmPrimitiveVisitor;
15import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor;
16import org.openstreetmap.josm.spi.preferences.Config;
17import org.openstreetmap.josm.tools.CopyList;
18import org.openstreetmap.josm.tools.Pair;
19import org.openstreetmap.josm.tools.Utils;
20
21/**
22 * One full way, consisting of a list of way {@link Node nodes}.
23 *
24 * @author imi
25 * @since 64
26 */
27public final class Way extends OsmPrimitive implements IWay {
28
29 /**
30 * All way nodes in this way
31 *
32 */
33 private Node[] nodes = new Node[0];
34 private BBox bbox;
35
36 /**
37 *
38 * You can modify returned list but changes will not be propagated back
39 * to the Way. Use {@link #setNodes(List)} to update this way
40 * @return Nodes composing the way
41 * @since 1862
42 */
43 public List<Node> getNodes() {
44 return new CopyList<>(nodes);
45 }
46
47 /**
48 * Set new list of nodes to way. This method is preferred to multiple calls to addNode/removeNode
49 * and similar methods because nodes are internally saved as array which means lower memory overhead
50 * but also slower modifying operations.
51 * @param nodes New way nodes. Can be null, in that case all way nodes are removed
52 * @since 1862
53 */
54 public void setNodes(List<Node> nodes) {
55 checkDatasetNotReadOnly();
56 boolean locked = writeLock();
57 try {
58 for (Node node:this.nodes) {
59 node.removeReferrer(this);
60 node.clearCachedStyle();
61 }
62
63 if (nodes == null) {
64 this.nodes = new Node[0];
65 } else {
66 this.nodes = nodes.toArray(new Node[0]);
67 }
68 for (Node node: this.nodes) {
69 node.addReferrer(this);
70 node.clearCachedStyle();
71 }
72
73 clearCachedStyle();
74 fireNodesChanged();
75 } finally {
76 writeUnlock(locked);
77 }
78 }
79
80 /**
81 * Prevent directly following identical nodes in ways.
82 * @param nodes list of nodes
83 * @return {@code nodes} with consecutive identical nodes removed
84 */
85 private static List<Node> removeDouble(List<Node> nodes) {
86 Node last = null;
87 int count = nodes.size();
88 for (int i = 0; i < count && count > 2;) {
89 Node n = nodes.get(i);
90 if (last == n) {
91 nodes.remove(i);
92 --count;
93 } else {
94 last = n;
95 ++i;
96 }
97 }
98 return nodes;
99 }
100
101 @Override
102 public int getNodesCount() {
103 return nodes.length;
104 }
105
106 /**
107 * Replies the real number of nodes in this way (full number of nodes minus one if this way is closed)
108 *
109 * @return the real number of nodes in this way.
110 *
111 * @see #getNodesCount()
112 * @see #isClosed()
113 * @since 5847
114 */
115 public int getRealNodesCount() {
116 int count = getNodesCount();
117 return isClosed() ? count-1 : count;
118 }
119
120 /**
121 * Replies the node at position <code>index</code>.
122 *
123 * @param index the position
124 * @return the node at position <code>index</code>
125 * @throws IndexOutOfBoundsException if <code>index</code> &lt; 0
126 * or <code>index</code> &gt;= {@link #getNodesCount()}
127 * @since 1862
128 */
129 public Node getNode(int index) {
130 return nodes[index];
131 }
132
133 @Override
134 public long getNodeId(int idx) {
135 return nodes[idx].getUniqueId();
136 }
137
138 /**
139 * Replies true if this way contains the node <code>node</code>, false
140 * otherwise. Replies false if <code>node</code> is null.
141 *
142 * @param node the node. May be null.
143 * @return true if this way contains the node <code>node</code>, false
144 * otherwise
145 * @since 1911
146 */
147 public boolean containsNode(Node node) {
148 if (node == null) return false;
149
150 Node[] nodes = this.nodes;
151 for (Node n : nodes) {
152 if (n.equals(node))
153 return true;
154 }
155 return false;
156 }
157
158 /**
159 * Return nodes adjacent to <code>node</code>
160 *
161 * @param node the node. May be null.
162 * @return Set of nodes adjacent to <code>node</code>
163 * @since 4671
164 */
165 public Set<Node> getNeighbours(Node node) {
166 Set<Node> neigh = new HashSet<>();
167
168 if (node == null) return neigh;
169
170 Node[] nodes = this.nodes;
171 for (int i = 0; i < nodes.length; i++) {
172 if (nodes[i].equals(node)) {
173 if (i > 0)
174 neigh.add(nodes[i-1]);
175 if (i < nodes.length-1)
176 neigh.add(nodes[i+1]);
177 }
178 }
179 return neigh;
180 }
181
182 /**
183 * Replies the ordered {@link List} of chunks of this way. Each chunk is replied as a {@link Pair} of {@link Node nodes}.
184 * @param sort If true, the nodes of each pair are sorted as defined by {@link Pair#sort}.
185 * If false, Pair.a and Pair.b are in the way order
186 * (i.e for a given Pair(n), Pair(n-1).b == Pair(n).a, Pair(n).b == Pair(n+1).a, etc.)
187 * @return The ordered list of chunks of this way.
188 * @since 3348
189 */
190 public List<Pair<Node, Node>> getNodePairs(boolean sort) {
191 List<Pair<Node, Node>> chunkSet = new ArrayList<>();
192 if (isIncomplete()) return chunkSet;
193 Node lastN = null;
194 Node[] nodes = this.nodes;
195 for (Node n : nodes) {
196 if (lastN == null) {
197 lastN = n;
198 continue;
199 }
200 Pair<Node, Node> np = new Pair<>(lastN, n);
201 if (sort) {
202 Pair.sort(np);
203 }
204 chunkSet.add(np);
205 lastN = n;
206 }
207 return chunkSet;
208 }
209
210 @Override public void accept(OsmPrimitiveVisitor visitor) {
211 visitor.visit(this);
212 }
213
214 @Override public void accept(PrimitiveVisitor visitor) {
215 visitor.visit(this);
216 }
217
218 protected Way(long id, boolean allowNegative) {
219 super(id, allowNegative);
220 }
221
222 /**
223 * Contructs a new {@code Way} with id 0.
224 * @since 86
225 */
226 public Way() {
227 super(0, false);
228 }
229
230 /**
231 * Contructs a new {@code Way} from an existing {@code Way}.
232 * @param original The original {@code Way} to be identically cloned. Must not be null
233 * @param clearMetadata If {@code true}, clears the OSM id and other metadata as defined by {@link #clearOsmMetadata}.
234 * If {@code false}, does nothing
235 * @since 2410
236 */
237 public Way(Way original, boolean clearMetadata) {
238 super(original.getUniqueId(), true);
239 cloneFrom(original);
240 if (clearMetadata) {
241 clearOsmMetadata();
242 }
243 }
244
245 /**
246 * Contructs a new {@code Way} from an existing {@code Way} (including its id).
247 * @param original The original {@code Way} to be identically cloned. Must not be null
248 * @since 86
249 */
250 public Way(Way original) {
251 this(original, false);
252 }
253
254 /**
255 * Contructs a new {@code Way} for the given id. If the id &gt; 0, the way is marked
256 * as incomplete. If id == 0 then way is marked as new
257 *
258 * @param id the id. &gt;= 0 required
259 * @throws IllegalArgumentException if id &lt; 0
260 * @since 343
261 */
262 public Way(long id) {
263 super(id, false);
264 }
265
266 /**
267 * Contructs a new {@code Way} with given id and version.
268 * @param id the id. &gt;= 0 required
269 * @param version the version
270 * @throws IllegalArgumentException if id &lt; 0
271 * @since 2620
272 */
273 public Way(long id, int version) {
274 super(id, version, false);
275 }
276
277 @Override
278 public void load(PrimitiveData data) {
279 if (!(data instanceof WayData))
280 throw new IllegalArgumentException("Not a way data: " + data);
281 boolean locked = writeLock();
282 try {
283 super.load(data);
284
285 WayData wayData = (WayData) data;
286
287 if (!wayData.getNodes().isEmpty() && getDataSet() == null) {
288 throw new AssertionError("Data consistency problem - way without dataset detected");
289 }
290
291 List<Node> newNodes = new ArrayList<>(wayData.getNodes().size());
292 for (Long nodeId : wayData.getNodes()) {
293 Node node = (Node) getDataSet().getPrimitiveById(nodeId, OsmPrimitiveType.NODE);
294 if (node != null) {
295 newNodes.add(node);
296 } else {
297 throw new AssertionError("Data consistency problem - way with missing node detected");
298 }
299 }
300 setNodes(newNodes);
301 } finally {
302 writeUnlock(locked);
303 }
304 }
305
306 @Override
307 public WayData save() {
308 WayData data = new WayData();
309 saveCommonAttributes(data);
310 for (Node node:nodes) {
311 data.getNodes().add(node.getUniqueId());
312 }
313 return data;
314 }
315
316 @Override
317 public void cloneFrom(OsmPrimitive osm) {
318 if (!(osm instanceof Way))
319 throw new IllegalArgumentException("Not a way: " + osm);
320 boolean locked = writeLock();
321 try {
322 super.cloneFrom(osm);
323 Way otherWay = (Way) osm;
324 setNodes(otherWay.getNodes());
325 } finally {
326 writeUnlock(locked);
327 }
328 }
329
330 @Override
331 public String toString() {
332 String nodesDesc = isIncomplete() ? "(incomplete)" : ("nodes=" + Arrays.toString(nodes));
333 return "{Way id=" + getUniqueId() + " version=" + getVersion()+ ' ' + getFlagsAsString() + ' ' + nodesDesc + '}';
334 }
335
336 @Override
337 public boolean hasEqualSemanticAttributes(OsmPrimitive other, boolean testInterestingTagsOnly) {
338 if (!(other instanceof Way))
339 return false;
340 Way w = (Way) other;
341 if (getNodesCount() != w.getNodesCount()) return false;
342 if (!super.hasEqualSemanticAttributes(other, testInterestingTagsOnly))
343 return false;
344 for (int i = 0; i < getNodesCount(); i++) {
345 if (!getNode(i).hasEqualSemanticAttributes(w.getNode(i)))
346 return false;
347 }
348 return true;
349 }
350
351 @Override
352 public int compareTo(OsmPrimitive o) {
353 if (o instanceof Relation)
354 return 1;
355 return o instanceof Way ? Long.compare(getUniqueId(), o.getUniqueId()) : -1;
356 }
357
358 /**
359 * Removes the given {@link Node} from this way. Ignored, if n is null.
360 * @param n The node to remove. Ignored, if null
361 * @since 1463
362 */
363 public void removeNode(Node n) {
364 checkDatasetNotReadOnly();
365 if (n == null || isIncomplete()) return;
366 boolean locked = writeLock();
367 try {
368 boolean closed = lastNode() == n && firstNode() == n;
369 int i;
370 List<Node> copy = getNodes();
371 while ((i = copy.indexOf(n)) >= 0) {
372 copy.remove(i);
373 }
374 i = copy.size();
375 if (closed && i > 2) {
376 copy.add(copy.get(0));
377 } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
378 copy.remove(i-1);
379 }
380 setNodes(removeDouble(copy));
381 n.clearCachedStyle();
382 } finally {
383 writeUnlock(locked);
384 }
385 }
386
387 /**
388 * Removes the given set of {@link Node nodes} from this way. Ignored, if selection is null.
389 * @param selection The selection of nodes to remove. Ignored, if null
390 * @since 5408
391 */
392 public void removeNodes(Set<? extends Node> selection) {
393 checkDatasetNotReadOnly();
394 if (selection == null || isIncomplete()) return;
395 boolean locked = writeLock();
396 try {
397 boolean closed = isClosed() && selection.contains(lastNode());
398 List<Node> copy = new ArrayList<>();
399
400 for (Node n: nodes) {
401 if (!selection.contains(n)) {
402 copy.add(n);
403 }
404 }
405
406 int i = copy.size();
407 if (closed && i > 2) {
408 copy.add(copy.get(0));
409 } else if (i >= 2 && i <= 3 && copy.get(0) == copy.get(i-1)) {
410 copy.remove(i-1);
411 }
412 setNodes(removeDouble(copy));
413 for (Node n : selection) {
414 n.clearCachedStyle();
415 }
416 } finally {
417 writeUnlock(locked);
418 }
419 }
420
421 /**
422 * Adds a node to the end of the list of nodes. Ignored, if n is null.
423 *
424 * @param n the node. Ignored, if null
425 * @throws IllegalStateException if this way is marked as incomplete. We can't add a node
426 * to an incomplete way
427 * @since 1313
428 */
429 public void addNode(Node n) {
430 checkDatasetNotReadOnly();
431 if (n == null) return;
432
433 boolean locked = writeLock();
434 try {
435 if (isIncomplete())
436 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
437 clearCachedStyle();
438 n.addReferrer(this);
439 nodes = Utils.addInArrayCopy(nodes, n);
440 n.clearCachedStyle();
441 fireNodesChanged();
442 } finally {
443 writeUnlock(locked);
444 }
445 }
446
447 /**
448 * Adds a node at position offs.
449 *
450 * @param offs the offset
451 * @param n the node. Ignored, if null.
452 * @throws IllegalStateException if this way is marked as incomplete. We can't add a node
453 * to an incomplete way
454 * @throws IndexOutOfBoundsException if offs is out of bounds
455 * @since 1313
456 */
457 public void addNode(int offs, Node n) {
458 checkDatasetNotReadOnly();
459 if (n == null) return;
460
461 boolean locked = writeLock();
462 try {
463 if (isIncomplete())
464 throw new IllegalStateException(tr("Cannot add node {0} to incomplete way {1}.", n.getId(), getId()));
465
466 clearCachedStyle();
467 n.addReferrer(this);
468 Node[] newNodes = new Node[nodes.length + 1];
469 System.arraycopy(nodes, 0, newNodes, 0, offs);
470 System.arraycopy(nodes, offs, newNodes, offs + 1, nodes.length - offs);
471 newNodes[offs] = n;
472 nodes = newNodes;
473 n.clearCachedStyle();
474 fireNodesChanged();
475 } finally {
476 writeUnlock(locked);
477 }
478 }
479
480 @Override
481 public void setDeleted(boolean deleted) {
482 boolean locked = writeLock();
483 try {
484 for (Node n:nodes) {
485 if (deleted) {
486 n.removeReferrer(this);
487 } else {
488 n.addReferrer(this);
489 }
490 n.clearCachedStyle();
491 }
492 fireNodesChanged();
493 super.setDeleted(deleted);
494 } finally {
495 writeUnlock(locked);
496 }
497 }
498
499 @Override
500 public boolean isClosed() {
501 if (isIncomplete()) return false;
502
503 Node[] nodes = this.nodes;
504 return nodes.length >= 3 && nodes[nodes.length-1] == nodes[0];
505 }
506
507 /**
508 * Determines if this way denotes an area (closed way with at least three distinct nodes).
509 * @return {@code true} if this way is closed and contains at least three distinct nodes
510 * @see #isClosed
511 * @since 5490
512 */
513 public boolean isArea() {
514 if (this.nodes.length >= 4 && isClosed()) {
515 Node distinctNode = null;
516 for (int i = 1; i < nodes.length-1; i++) {
517 if (distinctNode == null && nodes[i] != nodes[0]) {
518 distinctNode = nodes[i];
519 } else if (distinctNode != null && nodes[i] != nodes[0] && nodes[i] != distinctNode) {
520 return true;
521 }
522 }
523 }
524 return false;
525 }
526
527 /**
528 * Returns the last node of this way.
529 * The result equals <tt>{@link #getNode getNode}({@link #getNodesCount getNodesCount} - 1)</tt>.
530 * @return the last node of this way
531 * @since 1400
532 */
533 public Node lastNode() {
534 Node[] nodes = this.nodes;
535 if (isIncomplete() || nodes.length == 0) return null;
536 return nodes[nodes.length-1];
537 }
538
539 /**
540 * Returns the first node of this way.
541 * The result equals {@link #getNode getNode}{@code (0)}.
542 * @return the first node of this way
543 * @since 1400
544 */
545 public Node firstNode() {
546 Node[] nodes = this.nodes;
547 if (isIncomplete() || nodes.length == 0) return null;
548 return nodes[0];
549 }
550
551 /**
552 * Replies true if the given node is the first or the last one of this way, false otherwise.
553 * @param n The node to test
554 * @return true if the {@code n} is the first or the last node, false otherwise.
555 * @since 1400
556 */
557 public boolean isFirstLastNode(Node n) {
558 Node[] nodes = this.nodes;
559 if (isIncomplete() || nodes.length == 0) return false;
560 return n == nodes[0] || n == nodes[nodes.length -1];
561 }
562
563 /**
564 * Replies true if the given node is an inner node of this way, false otherwise.
565 * @param n The node to test
566 * @return true if the {@code n} is an inner node, false otherwise.
567 * @since 3515
568 */
569 public boolean isInnerNode(Node n) {
570 Node[] nodes = this.nodes;
571 if (isIncomplete() || nodes.length <= 2) return false;
572 /* circular ways have only inner nodes, so return true for them! */
573 if (n == nodes[0] && n == nodes[nodes.length-1]) return true;
574 for (int i = 1; i < nodes.length - 1; ++i) {
575 if (nodes[i] == n) return true;
576 }
577 return false;
578 }
579
580 @Override
581 public String getDisplayName(NameFormatter formatter) {
582 return formatter.format(this);
583 }
584
585 @Override
586 public OsmPrimitiveType getType() {
587 return OsmPrimitiveType.WAY;
588 }
589
590 @Override
591 public OsmPrimitiveType getDisplayType() {
592 return isClosed() ? OsmPrimitiveType.CLOSEDWAY : OsmPrimitiveType.WAY;
593 }
594
595 private void checkNodes() {
596 DataSet dataSet = getDataSet();
597 if (dataSet != null) {
598 Node[] nodes = this.nodes;
599 for (Node n: nodes) {
600 if (n.getDataSet() != dataSet)
601 throw new DataIntegrityProblemException("Nodes in way must be in the same dataset",
602 tr("Nodes in way must be in the same dataset"));
603 if (n.isDeleted())
604 throw new DataIntegrityProblemException("Deleted node referenced: " + toString(),
605 "<html>" + tr("Deleted node referenced by {0}",
606 DefaultNameFormatter.getInstance().formatAsHtmlUnorderedList(this)) + "</html>");
607 }
608 if (Config.getPref().getBoolean("debug.checkNullCoor", true)) {
609 for (Node n: nodes) {
610 if (n.isVisible() && !n.isIncomplete() && !n.isLatLonKnown())
611 throw new DataIntegrityProblemException("Complete visible node with null coordinates: " + toString(),
612 "<html>" + tr("Complete node {0} with null coordinates in way {1}",
613 DefaultNameFormatter.getInstance().formatAsHtmlUnorderedList(n),
614 DefaultNameFormatter.getInstance().formatAsHtmlUnorderedList(this)) + "</html>");
615 }
616 }
617 }
618 }
619
620 private void fireNodesChanged() {
621 checkNodes();
622 if (getDataSet() != null) {
623 getDataSet().fireWayNodesChanged(this);
624 }
625 }
626
627 @Override
628 void setDataset(DataSet dataSet) {
629 super.setDataset(dataSet);
630 checkNodes();
631 }
632
633 @Override
634 public BBox getBBox() {
635 if (getDataSet() == null)
636 return new BBox(this);
637 if (bbox == null) {
638 bbox = new BBox(this);
639 }
640 return new BBox(bbox);
641 }
642
643 @Override
644 protected void addToBBox(BBox box, Set<PrimitiveId> visited) {
645 box.add(getBBox());
646 }
647
648 @Override
649 public void updatePosition() {
650 bbox = new BBox(this);
651 }
652
653 /**
654 * Replies true if this way has incomplete nodes, false otherwise.
655 * @return true if this way has incomplete nodes, false otherwise.
656 * @since 2587
657 */
658 public boolean hasIncompleteNodes() {
659 Node[] nodes = this.nodes;
660 for (Node node : nodes) {
661 if (node.isIncomplete())
662 return true;
663 }
664 return false;
665 }
666
667 /**
668 * Replies true if all nodes of the way have known lat/lon, false otherwise.
669 * @return true if all nodes of the way have known lat/lon, false otherwise
670 * @since 13033
671 */
672 public boolean hasOnlyLocatableNodes() {
673 Node[] nodes = this.nodes;
674 for (Node node : nodes) {
675 if (!node.isLatLonKnown())
676 return false;
677 }
678 return true;
679 }
680
681 @Override
682 public boolean isUsable() {
683 return super.isUsable() && !hasIncompleteNodes();
684 }
685
686 @Override
687 public boolean isDrawable() {
688 return super.isDrawable() && hasOnlyLocatableNodes();
689 }
690
691 /**
692 * Replies the length of the way, in metres, as computed by {@link LatLon#greatCircleDistance}.
693 * @return The length of the way, in metres
694 * @since 4138
695 */
696 public double getLength() {
697 double length = 0;
698 Node lastN = null;
699 for (Node n:nodes) {
700 if (lastN != null) {
701 LatLon lastNcoor = lastN.getCoor();
702 LatLon coor = n.getCoor();
703 if (lastNcoor != null && coor != null) {
704 length += coor.greatCircleDistance(lastNcoor);
705 }
706 }
707 lastN = n;
708 }
709 return length;
710 }
711
712 /**
713 * Replies the length of the longest segment of the way, in metres, as computed by {@link LatLon#greatCircleDistance}.
714 * @return The length of the segment, in metres
715 * @since 8320
716 */
717 public double getLongestSegmentLength() {
718 double length = 0;
719 Node lastN = null;
720 for (Node n:nodes) {
721 if (lastN != null) {
722 LatLon lastNcoor = lastN.getCoor();
723 LatLon coor = n.getCoor();
724 if (lastNcoor != null && coor != null) {
725 double l = coor.greatCircleDistance(lastNcoor);
726 if (l > length) {
727 length = l;
728 }
729 }
730 }
731 lastN = n;
732 }
733 return length;
734 }
735
736 /**
737 * Tests if this way is a oneway.
738 * @return {@code 1} if the way is a oneway,
739 * {@code -1} if the way is a reversed oneway,
740 * {@code 0} otherwise.
741 * @since 5199
742 */
743 public int isOneway() {
744 String oneway = get("oneway");
745 if (oneway != null) {
746 if ("-1".equals(oneway)) {
747 return -1;
748 } else {
749 Boolean isOneway = OsmUtils.getOsmBoolean(oneway);
750 if (isOneway != null && isOneway) {
751 return 1;
752 }
753 }
754 }
755 return 0;
756 }
757
758 /**
759 * Replies the first node of this way, respecting or not its oneway state.
760 * @param respectOneway If true and if this way is a reversed oneway, replies the last node. Otherwise, replies the first node.
761 * @return the first node of this way, according to {@code respectOneway} and its oneway state.
762 * @since 5199
763 */
764 public Node firstNode(boolean respectOneway) {
765 return !respectOneway || isOneway() != -1 ? firstNode() : lastNode();
766 }
767
768 /**
769 * Replies the last node of this way, respecting or not its oneway state.
770 * @param respectOneway If true and if this way is a reversed oneway, replies the first node. Otherwise, replies the last node.
771 * @return the last node of this way, according to {@code respectOneway} and its oneway state.
772 * @since 5199
773 */
774 public Node lastNode(boolean respectOneway) {
775 return !respectOneway || isOneway() != -1 ? lastNode() : firstNode();
776 }
777
778 @Override
779 public boolean concernsArea() {
780 return hasAreaTags();
781 }
782
783 @Override
784 public boolean isOutsideDownloadArea() {
785 for (final Node n : nodes) {
786 if (n.isOutsideDownloadArea()) {
787 return true;
788 }
789 }
790 return false;
791 }
792
793 @Override
794 protected void keysChangedImpl(Map<String, String> originalKeys) {
795 super.keysChangedImpl(originalKeys);
796 clearCachedNodeStyles();
797 }
798
799 /**
800 * Clears all cached styles for all nodes of this way. This should not be called from outside.
801 * @see Node#clearCachedStyle()
802 */
803 public void clearCachedNodeStyles() {
804 for (final Node n : nodes) {
805 n.clearCachedStyle();
806 }
807 }
808}
Note: See TracBrowser for help on using the repository browser.