// This software is released into the Public Domain. See copying.txt for details. package org.openstreetmap.osmosis.core.domain.v0_6; import java.util.ArrayList; import java.util.Collection; import java.util.Collections; import java.util.Date; import java.util.Iterator; import java.util.List; import org.openstreetmap.osmosis.core.domain.common.SimpleTimestampContainer; import org.openstreetmap.osmosis.core.domain.common.TimestampContainer; import org.openstreetmap.osmosis.core.store.StoreClassRegister; import org.openstreetmap.osmosis.core.store.StoreReader; import org.openstreetmap.osmosis.core.store.StoreWriter; /** * A data class representing a single OSM way. * * @author Brett Henderson */ public class Way extends Entity implements Comparable<Way> { private List<WayNode> wayNodes; /** * Creates a new instance. * * @param id * The unique identifier. * @param version * The version of the entity. * @param timestamp * The last updated timestamp. * @param user * The user that last modified this entity. * @param changesetId * The id of the changeset that this version of the entity was created by. * @deprecated As of 0.40, replaced by Way(entityData). */ public Way(long id, int version, Date timestamp, OsmUser user, long changesetId) { // Chain to the more specific constructor this(id, version, new SimpleTimestampContainer(timestamp), user, changesetId); } /** * Creates a new instance. * * @param id * The unique identifier. * @param version * The version of the entity. * @param timestampContainer * The container holding the timestamp in an alternative * timestamp representation. * @param user * The name of the user that last modified this entity. * @param changesetId * The id of the changeset that this version of the entity was created by. * @deprecated As of 0.40, replaced by Way(entityData). */ public Way(long id, int version, TimestampContainer timestampContainer, OsmUser user, long changesetId) { super(id, version, timestampContainer, user, changesetId); this.wayNodes = new ArrayList<WayNode>(); } /** * Creates a new instance. * * @param entityData * The common entity data. */ public Way(CommonEntityData entityData) { super(entityData); this.wayNodes = new ArrayList<WayNode>(); } /** * Creates a new instance. * * @param id * The unique identifier. * @param version * The version of the entity. * @param timestamp * The last updated timestamp. * @param user * The user that last modified this entity. * @param changesetId * The id of the changeset that this version of the entity was created by. * @param tags * The tags to apply to the object. * @param wayNodes * The way nodes to apply to the object * @deprecated As of 0.40, replaced by Way(entityData, wayNodes). */ public Way(long id, int version, Date timestamp, OsmUser user, long changesetId, Collection<Tag> tags, List<WayNode> wayNodes) { // Chain to the more specific constructor this(id, version, new SimpleTimestampContainer(timestamp), user, changesetId, tags, wayNodes); } /** * Creates a new instance. * * @param id * The unique identifier. * @param version * The version of the entity. * @param timestampContainer * The container holding the timestamp in an alternative * timestamp representation. * @param user * The name of the user that last modified this entity. * @param changesetId * The id of the changeset that this version of the entity was created by. * @param tags * The tags to apply to the object. * @param wayNodes * The way nodes to apply to the object * @deprecated As of 0.40, replaced by Way(entityData, wayNodes). */ public Way( long id, int version, TimestampContainer timestampContainer, OsmUser user, long changesetId, Collection<Tag> tags, List<WayNode> wayNodes) { super(id, version, timestampContainer, user, changesetId, tags); this.wayNodes = new ArrayList<WayNode>(wayNodes); } /** * Creates a new instance. * * @param entityData * The common entity data. * @param wayNodes * The way nodes to apply to the object */ public Way( CommonEntityData entityData, List<WayNode> wayNodes) { super(entityData); this.wayNodes = new ArrayList<WayNode>(wayNodes); } /** * Creates a new instance. * * @param originalWay * The way to clone from. */ private Way(Way originalWay) { super(originalWay); this.wayNodes = new ArrayList<WayNode>(originalWay.wayNodes); } /** * Creates a new instance. * * @param sr * The store to read state from. * @param scr * Maintains the mapping between classes and their identifiers * within the store. */ public Way(StoreReader sr, StoreClassRegister scr) { super(sr, scr); int featureCount; featureCount = sr.readInteger(); wayNodes = new ArrayList<WayNode>(); for (int i = 0; i < featureCount; i++) { wayNodes.add(new WayNode(sr, scr)); } } /** * {@inheritDoc} */ @Override public void store(StoreWriter sw, StoreClassRegister scr) { super.store(sw, scr); sw.writeInteger(wayNodes.size()); for (WayNode wayNode : wayNodes) { wayNode.store(sw, scr); } } /** * {@inheritDoc} */ @Override public EntityType getType() { return EntityType.Way; } /** * {@inheritDoc} */ @Override public boolean equals(Object o) { if (o instanceof Way) { return compareTo((Way) o) == 0; } else { return false; } } /** * {@inheritDoc} */ @Override public int hashCode() { /* * As per the hashCode definition, this doesn't have to be unique it * just has to return the same value for any two objects that compare * equal. Using both id and version will provide a good distribution of * values but is simple to calculate. */ return (int) getId() + getVersion(); } /** * Compares this node list to the specified node list. The comparison is * based on a direct comparison of the node ids. * * @param comparisonWayNodes * The node list to compare to. * @return 0 if equal, < 0 if considered "smaller", and > 0 if * considered "bigger". */ protected int compareWayNodes(List<WayNode> comparisonWayNodes) { Iterator<WayNode> i; Iterator<WayNode> j; // The list with the most entities is considered bigger. if (wayNodes.size() != comparisonWayNodes.size()) { return wayNodes.size() - comparisonWayNodes.size(); } // Check the individual way nodes. i = wayNodes.iterator(); j = comparisonWayNodes.iterator(); while (i.hasNext()) { int result = i.next().compareTo(j.next()); if (result != 0) { return result; } } // There are no differences. return 0; } /** * Compares this way to the specified way. The way comparison is based on a * comparison of id, version, timestamp, wayNodeList and tags in that order. * * @param comparisonWay * The way to compare to. * @return 0 if equal, < 0 if considered "smaller", and > 0 if * considered "bigger". */ public int compareTo(Way comparisonWay) { int wayNodeListResult; if (this.getId() < comparisonWay.getId()) { return -1; } if (this.getId() > comparisonWay.getId()) { return 1; } if (this.getVersion() < comparisonWay.getVersion()) { return -1; } if (this.getVersion() > comparisonWay.getVersion()) { return 1; } if (this.getTimestamp() == null && comparisonWay.getTimestamp() != null) { return -1; } if (this.getTimestamp() != null && comparisonWay.getTimestamp() == null) { return 1; } if (this.getTimestamp() != null && comparisonWay.getTimestamp() != null) { int result; result = this.getTimestamp().compareTo(comparisonWay.getTimestamp()); if (result != 0) { return result; } } wayNodeListResult = compareWayNodes( comparisonWay.getWayNodes() ); if (wayNodeListResult != 0) { return wayNodeListResult; } return compareTags(comparisonWay.getTags()); } /** * {@inheritDoc} */ @Override public void makeReadOnly() { if (!isReadOnly()) { wayNodes = Collections.unmodifiableList(wayNodes); } super.makeReadOnly(); } /** * Returns the attached list of way nodes. The returned list is read-only. * * @return The wayNodeList. */ public List<WayNode> getWayNodes() { return wayNodes; } /** * {@inheritDoc} */ @Override public Way getWriteableInstance() { if (isReadOnly()) { return new Way(this); } else { return this; } } /** * Is this way closed? (A way is closed if the first node id equals the last node id.) * * @return True or false */ public boolean isClosed() { return wayNodes.get(0).getNodeId() == wayNodes.get(wayNodes.size() - 1).getNodeId(); } /** * ${@inheritDoc}. */ @Override public String toString() { String name = null; Collection<Tag> tags = getTags(); for (Tag tag : tags) { if (tag.getKey() != null && tag.getKey().equalsIgnoreCase("name")) { name = tag.getValue(); break; } } if (name != null) { return "Way(id=" + getId() + ", #tags=" + getTags().size() + ", name='" + name + "')"; } return "Way(id=" + getId() + ", #tags=" + getTags().size() + ")"; } }