package org.openstreetmap.josm.plugins.graphview.core.data.osmosis;
import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Collection;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import org.openstreetmap.josm.plugins.graphview.core.data.DataSource;
import org.openstreetmap.josm.plugins.graphview.core.data.DataSourceObserver;
import org.openstreetmap.josm.plugins.graphview.core.data.MapBasedTagGroup;
import org.openstreetmap.josm.plugins.graphview.core.data.TagGroup;
import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer;
import org.openstreetmap.osmosis.core.domain.v0_6.Entity;
import org.openstreetmap.osmosis.core.domain.v0_6.EntityType;
import org.openstreetmap.osmosis.core.domain.v0_6.Node;
import org.openstreetmap.osmosis.core.domain.v0_6.Relation;
import org.openstreetmap.osmosis.core.domain.v0_6.Tag;
import org.openstreetmap.osmosis.core.domain.v0_6.Way;
import org.openstreetmap.osmosis.core.domain.v0_6.WayNode;
import org.openstreetmap.osmosis.core.task.v0_6.Sink;
import org.openstreetmap.osmosis.xml.common.CompressionMethod;
import org.openstreetmap.osmosis.xml.v0_6.XmlReader;
/**
* DataSource providing information from a single .osm file. The file is read
* during the constructor call, there will be no updates when the file is
* changed later. This class uses osmosis to read the file.
*/
public class OSMFileDataSource implements
DataSource<OSMFileDataSource.OwnNode, OSMFileDataSource.OwnWay,
OSMFileDataSource.OwnRelation, OSMFileDataSource.OwnMember> {
private static final boolean useDebugLabels = true;
private boolean complete = false;
private synchronized boolean isComplete() {
return complete;
}
private synchronized void setCompleteTrue() {
this.complete = true;
}
private Map<Long, Node> nodesById = new HashMap<Long, Node>();
private Map<Long, Way> waysById = new HashMap<Long, Way>();
private Map<Long, Relation> relationsById = new HashMap<Long, Relation>();
private Collection<OwnNode> ownNodes;
private Collection<OwnWay> ownWays;
private Collection<OwnRelation> ownRelations;
private final Sink sinkImplementation = new Sink() {
public void initialize(Map<String, Object> arg0) {
/* do nothing */
}
public void release() {
/* do nothing */
}
public void complete() {
setCompleteTrue();
}
public void process(EntityContainer entityContainer) {
Entity entity = entityContainer.getEntity();
if (entity instanceof Node) {
nodesById.put(entity.getId(), ((Node) entity));
} else if (entity instanceof Way) {
waysById.put(entity.getId(), ((Way) entity));
} else if (entity instanceof Relation) {
relationsById.put(entity.getId(), ((Relation) entity));
}
}
};
public OSMFileDataSource(File file) throws IOException {
XmlReader reader = new XmlReader(file, false, CompressionMethod.None);
reader.setSink(sinkImplementation);
Thread readerThread = new Thread(reader);
readerThread.start();
while (readerThread.isAlive()) {
try {
readerThread.join();
} catch (InterruptedException e) { /* do nothing */
}
}
if (!isComplete()) {
throw new IOException("couldn't read from file");
}
convertToOwnRepresentation();
}
private void convertToOwnRepresentation() {
ownNodes = new ArrayList<OwnNode>(nodesById.size());
ownWays = new ArrayList<OwnWay>(waysById.size());
ownRelations = new ArrayList<OwnRelation>(relationsById.size());
Map<Node, OwnNode> nodeMap = new HashMap<Node, OwnNode>();
Map<Way, OwnWay> wayMap = new HashMap<Way, OwnWay>();
Map<Relation, OwnRelation> relationMap = new HashMap<Relation, OwnRelation>();
for (Node node : nodesById.values()) {
OwnNode ownNode = new OwnNode(node.getLatitude(), node
.getLongitude(), tagGroupForEntity(node));
ownNodes.add(ownNode);
nodeMap.put(node, ownNode);
}
for (Way way : waysById.values()) {
List<WayNode> origWayNodes = way.getWayNodes();
List<OwnNode> wayNodes = new ArrayList<OwnNode>(origWayNodes.size());
for (WayNode origWayNode : origWayNodes) {
Node origNode = nodesById.get(origWayNode.getNodeId());
wayNodes.add(nodeMap.get(origNode));
}
OwnWay ownWay = new OwnWay(tagGroupForEntity(way), wayNodes);
ownWays.add(ownWay);
wayMap.put(way, ownWay);
}
for (Relation relation : relationsById.values()) {
OwnRelation ownRelation = new OwnRelation(
tagGroupForEntity(relation), relation.getMembers().size());
ownRelations.add(ownRelation);
relationMap.put(relation, ownRelation);
}
// add relation members
// (needs to be done *after* creation because relations can be members
// of other relations)
for (Relation relation : relationMap.keySet()) {
OwnRelation ownRelation = relationMap.get(relation);
for (org.openstreetmap.osmosis.core.domain.v0_6.RelationMember member : relation
.getMembers()) {
Object memberObject = null;
if (member.getMemberType() == EntityType.Node) {
memberObject = nodeMap.get(nodesById.get(member
.getMemberId()));
} else if (member.getMemberType() == EntityType.Way) {
memberObject = wayMap.get(waysById
.get(member.getMemberId()));
} else if (member.getMemberType() == EntityType.Relation) {
memberObject = relationMap.get(relationsById.get(member
.getMemberId()));
} else {
continue;
}
OwnMember ownMember = new OwnMember(member
.getMemberRole(), memberObject);
ownRelation.relationMembers.add(ownMember);
}
}
// give up references to original collections
nodesById = null;
waysById = null;
relationsById = null;
}
private TagGroup tagGroupForEntity(Entity entity) {
Map<String, String> tagMap = new HashMap<String, String>(entity.getTags().size());
for (Tag tag : entity.getTags()) {
tagMap.put(tag.getKey(), tag.getValue());
}
return new MapBasedTagGroup(tagMap);
}
public void addObserver(DataSourceObserver observer) {
// OSMFileDataSource doesn't check for updates
}
public void deleteObserver(DataSourceObserver observer) {
// OSMFileDataSource doesn't check for updates
}
public double getLat(OwnNode node) {
return node.lat;
}
public double getLon(OwnNode node) {
return node.lon;
}
public List<OwnMember> getMembers(OwnRelation relation) {
return relation.relationMembers;
}
public Collection<OwnNode> getNodes() {
return ownNodes;
}
public Collection<OwnWay> getWays() {
return ownWays;
}
public Collection<OwnRelation> getRelations() {
return ownRelations;
}
public List<OwnNode> getNodes(OwnWay way) {
return way.nodes;
}
public TagGroup getTagsN(OwnNode node) {
return node.tags;
}
public TagGroup getTagsR(OwnRelation relation) {
return relation.tags;
}
public TagGroup getTagsW(OwnWay way) {
return way.tags;
}
public Object getMember(OwnMember member) {
return member.member;
}
public String getRole(OwnMember member) {
return member.role;
}
public boolean isNMember(OwnMember member) {
return member.member instanceof OwnNode;
};
public boolean isWMember(OwnMember member) {
return member.member instanceof OwnWay;
};
public boolean isRMember(OwnMember member) {
return member.member instanceof OwnRelation;
};
public class OwnNode {
private final double lat;
private final double lon;
private final TagGroup tags;
public OwnNode(double lat, double lon, TagGroup tags) {
this.lat = lat;
this.lon = lon;
this.tags = tags;
}
@Override
public String toString() {
if (useDebugLabels && tags.containsKey("debug:label")) {
return tags.getValue("debug:label");
}
return "(" + lat + ", " + lon + ", " + tags + ")";
}
}
public class OwnWay {
private final TagGroup tags;
private final List<OwnNode> nodes;
public OwnWay(TagGroup tags, List<OwnNode> nodes) {
this.tags = tags;
this.nodes = nodes;
}
@Override
public String toString() {
if (useDebugLabels && tags.containsKey("debug:label")) {
return tags.getValue("debug:label");
}
return nodes.get(0)
+ "->[" + (nodes.size() - 2) + "]->"
+ nodes.get(nodes.size()-1);
}
}
public class OwnRelation {
private final TagGroup tags;
private final List<OwnMember> relationMembers;
// content added after constructor call
public OwnRelation(TagGroup tags, int initialMemberSize) {
this.tags = tags;
this.relationMembers =
new ArrayList<OwnMember>(initialMemberSize);
}
}
public static class OwnMember {
private final String role;
private final Object member;
public OwnMember(String role, Object member) {
this.role = role;
this.member = member;
}
}
}