001// License: GPL. For details, see LICENSE file. 002package org.openstreetmap.josm.data.vector; 003 004import java.util.ArrayList; 005import java.util.Collections; 006import java.util.List; 007import java.util.stream.Collectors; 008 009import org.openstreetmap.josm.data.osm.BBox; 010import org.openstreetmap.josm.data.osm.INode; 011import org.openstreetmap.josm.data.osm.IWay; 012import org.openstreetmap.josm.data.osm.OsmPrimitiveType; 013import org.openstreetmap.josm.data.osm.UniqueIdGenerator; 014import org.openstreetmap.josm.data.osm.visitor.PrimitiveVisitor; 015 016/** 017 * The "Way" type for a Vector layer 018 * 019 * @author Taylor Smock 020 * @since 17862 021 */ 022public class VectorWay extends VectorPrimitive implements IWay<VectorNode> { 023 private static final UniqueIdGenerator WAY_GENERATOR = new UniqueIdGenerator(); 024 private final List<VectorNode> nodes = new ArrayList<>(); 025 private BBox cachedBBox; 026 027 /** 028 * Create a new way for a layer 029 * @param layer The layer for the way 030 */ 031 public VectorWay(String layer) { 032 super(layer); 033 } 034 035 @Override 036 public UniqueIdGenerator getIdGenerator() { 037 return WAY_GENERATOR; 038 } 039 040 @Override 041 public void accept(PrimitiveVisitor visitor) { 042 visitor.visit(this); 043 } 044 045 @Override 046 public BBox getBBox() { 047 if (this.cachedBBox == null) { 048 BBox tBBox = new BBox(); 049 for (INode node : this.getNodes()) { 050 tBBox.add(node.getBBox()); 051 } 052 this.cachedBBox = tBBox.toImmutable(); 053 } 054 return this.cachedBBox; 055 } 056 057 @Override 058 public int getNodesCount() { 059 return this.getNodes().size(); 060 } 061 062 @Override 063 public VectorNode getNode(int index) { 064 return this.getNodes().get(index); 065 } 066 067 @Override 068 public List<VectorNode> getNodes() { 069 return Collections.unmodifiableList(this.nodes); 070 } 071 072 @Override 073 public void setNodes(List<VectorNode> nodes) { 074 this.nodes.forEach(node -> node.removeReferrer(this)); 075 this.nodes.clear(); 076 if (nodes != null) { 077 nodes.forEach(node -> node.addReferrer(this)); 078 this.nodes.addAll(nodes); 079 } 080 this.cachedBBox = null; 081 } 082 083 @Override 084 public List<Long> getNodeIds() { 085 return this.getNodes().stream().map(VectorNode::getId).collect(Collectors.toList()); 086 } 087 088 @Override 089 public long getNodeId(int idx) { 090 return this.getNodes().get(idx).getId(); 091 } 092 093 @Override 094 public boolean isClosed() { 095 return this.firstNode() != null && this.firstNode().equals(this.lastNode()); 096 } 097 098 @Override 099 public VectorNode firstNode() { 100 if (this.nodes.isEmpty()) { 101 return null; 102 } 103 return this.getNode(0); 104 } 105 106 @Override 107 public VectorNode lastNode() { 108 if (this.nodes.isEmpty()) { 109 return null; 110 } 111 return this.getNode(this.getNodesCount() - 1); 112 } 113 114 @Override 115 public boolean isFirstLastNode(INode n) { 116 if (this.nodes.isEmpty()) { 117 return false; 118 } 119 return this.firstNode().equals(n) || this.lastNode().equals(n); 120 } 121 122 @Override 123 public boolean isInnerNode(INode n) { 124 if (this.nodes.isEmpty()) { 125 return false; 126 } 127 return !this.firstNode().equals(n) && !this.lastNode().equals(n) && this.nodes.stream() 128 .anyMatch(vectorNode -> vectorNode.equals(n)); 129 } 130 131 @Override 132 public OsmPrimitiveType getType() { 133 return this.isClosed() ? OsmPrimitiveType.CLOSEDWAY : OsmPrimitiveType.WAY; 134 } 135}