package aimax.osm.data.impl;
import java.util.Collections;
import java.util.List;
import aimax.osm.data.BoundingBox;
import aimax.osm.data.EntityVisitor;
import aimax.osm.data.entities.MapNode;
import aimax.osm.data.entities.MapWay;
/**
* Default implementation of a node.
* @author Ruediger Lunde
*/
public class DefaultMapWay extends DefaultMapEntity implements MapWay {
private List<MapNode> nodes;
// Implicit (storage efficient) representation of a bounding box
private short latMinIdx;
private short lonMinIdx;
private short latMaxIdx;
private short lonMaxIdx;
/** Creates a way with a specified ID. */
public DefaultMapWay(long id) {
this.id = id;
nodes = Collections.emptyList();
latMinIdx = -1;
}
/** Assigns a way description (as list of nodes) to the way. */
public void setNodes(List<MapNode> nodes) {
this.nodes = nodes;
latMinIdx = -1;
}
/** {@inheritDoc} */
@Override
public boolean isOneway() {
return "yes".equals(getAttributeValue("oneway"));
}
/** {@inheritDoc} */
@Override
public boolean isArea() {
return "yes".equals(getAttributeValue("area"));
}
/** {@inheritDoc} */
@Override
public List<MapNode> getNodes() {
return Collections.unmodifiableList(nodes);
}
/** {@inheritDoc} */
@Override
public void accept(EntityVisitor visitor) {
visitor.visitMapWay(this);
}
/** {@inheritDoc} */
@Override
public BoundingBox computeBoundingBox() {
updateBoundingBox();
return new BoundingBox(nodes.get(latMinIdx).getLat(),
nodes.get(lonMinIdx).getLon(), nodes.get(latMaxIdx).getLat(),
nodes.get(lonMaxIdx).getLon());
}
/** {@inheritDoc} */
@Override
public float getBoundingBoxSize() {
updateBoundingBox();
float latDiff = nodes.get(latMaxIdx).getLat()
- nodes.get(latMinIdx).getLat();
float lonDiff = nodes.get(lonMaxIdx).getLon()
- nodes.get(lonMinIdx).getLon();
return latDiff + lonDiff;
// latDiff * latDiff
// + (float) Math.cos(nodes.get(latMinIdx).getLat() / 180.0 * Math.PI) *
// lonDiff * lonDiff;
}
private void updateBoundingBox() {
if (latMinIdx == -1) {
latMinIdx = 0;
lonMinIdx = 0;
latMaxIdx = 0;
lonMaxIdx = 0;
for (short i = 1; i < nodes.size(); i++) {
float lat = nodes.get(i).getLat();
float lon = nodes.get(i).getLon();
if (lat < nodes.get(latMinIdx).getLat())
latMinIdx = i;
else if (lat > nodes.get(latMaxIdx).getLat())
latMaxIdx = i;
if (lon < nodes.get(lonMinIdx).getLon())
lonMinIdx = i;
else if (lon > nodes.get(lonMaxIdx).getLon())
lonMaxIdx = i;
}
}
}
@Override
public String toString() {
StringBuffer result = new StringBuffer("Way(" + id + ", [ ");
for (MapNode node : nodes)
result.append(node.getId() + " ");
result.append("])");
return result.toString();
}
/////////////////////////////////////////////////////////////////
// extensions for KDTree
/** {@inheritDoc} */
@Override
public int compareLatitude(float lat) {
updateBoundingBox();
int result = ((DefaultMapNode) nodes.get(latMinIdx))
.compareLatitude(lat);
if (result != ((DefaultMapNode) nodes.get(latMaxIdx))
.compareLatitude(lat))
result = 0;
return result;
}
/** {@inheritDoc} */
@Override
public int compareLongitude(float lon) {
updateBoundingBox();
int result = ((DefaultMapNode) nodes.get(lonMinIdx))
.compareLongitude(lon);
if (result != ((DefaultMapNode) nodes.get(lonMaxIdx))
.compareLongitude(lon))
result = 0;
return result;
}
}