package nl.tudelft.simulation.dsol.animation.gis.osm; import java.awt.geom.Path2D; import java.util.HashMap; import java.util.Iterator; import java.util.List; import java.util.Map; 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.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 nl.tudelft.simulation.dsol.animation.gis.FeatureInterface; import nl.tudelft.simulation.dsol.animation.gis.GisObject; import nl.tudelft.simulation.dsol.animation.gis.SerializablePath; import nl.tudelft.simulation.dsol.animation.gis.transform.CoordinateTransform; /** * OsmLayerSink.java. *

* Copyright (c) 2021-2021 Delft University of Technology, Jaffalaan 5, 2628 BX Delft, the Netherlands. All rights reserved. See * for project information DSOL Manual. The DSOL * project is distributed under a three-clause BSD-style license, which can be found at * DSOL License. *

* @author Alexander Verbraeck */ public class OsmLayerSink implements Sink { /** the ways in the OSM file. */ private Map ways = new HashMap(); /** the nodes in the OSM file. */ private Map nodes = new HashMap(); /** the key - value pairs to read. There can be multiple values per key, or '*' for all. */ private final List featuresToRead; /** an optional transformation of the lat/lon (or other) coordinates. */ private final CoordinateTransform coordinateTransform; /** * Construct a sink to read the features form the OSM file. For OSM this the Feature list is typically the complete set of * features that needs to be read. It is rare that multiple OSM files are available for the data, but this could be the case * (e.g., state or country OSM files).
* TODO: add an optional initial extent in case the sounrce's extent is much larger than the extent we want to display * @param featuresToRead the features that the sink needs to read. * @param coordinateTransform CoordinateTransform; the transformation of (x, y) coordinates to (x', y') coordinates. */ public OsmLayerSink(final List featuresToRead, final CoordinateTransform coordinateTransform) { this.featuresToRead = featuresToRead; this.coordinateTransform = coordinateTransform; } /** {@inheritDoc} */ @Override public void process(final EntityContainer entityContainer) { Entity entity = entityContainer.getEntity(); if (entity instanceof Node) { this.nodes.put(entity.getId(), (Node) entity); Iterator tagIterator = entity.getTags().iterator(); while (tagIterator.hasNext()) { Tag tag = tagIterator.next(); String key = tag.getKey(); String value = tag.getValue(); // TODO: look whether we want to display special nodes. } } else if (entity instanceof Way) { boolean read = false; Iterator tagIterator = entity.getTags().iterator(); while (tagIterator.hasNext()) { Tag tag = tagIterator.next(); String key = tag.getKey(); String value = tag.getValue(); for (FeatureInterface feature : this.featuresToRead) { if (feature.getKey().equals("*")) { read = true; break; } if (feature.getKey().equals(key)) { if (feature.getValue().equals("*") || feature.getValue().equals(value)) { read = true; break; } } } if (read) { break; } } if (read) { this.ways.put(entity.getId(), (Way) entity); } } else if (entity instanceof Relation) { Iterator tagint = entity.getTags().iterator(); while (tagint.hasNext()) { Tag route = tagint.next(); } } } /** {@inheritDoc} */ @Override public void initialize(final Map metaData) { // nothing to do right now. } /** {@inheritDoc} */ @Override public void complete() { for (Way way : this.ways.values()) { boolean ready = false; Iterator tagIterator = way.getTags().iterator(); while (tagIterator.hasNext()) { Tag tag = tagIterator.next(); String key = tag.getKey(); String value = tag.getValue(); for (FeatureInterface feature : this.featuresToRead) { if (feature.getKey().equals("*")) { addWay(way, feature); ready = true; break; } if (feature.getKey().equals(key)) { if (feature.getValue().equals("*") || feature.getValue().equals(value)) { addWay(way, feature); ready = true; break; } } } if (ready) { break; } } } } /** * Add a way to a feature. * @param way Way; the way to add to the feature shape list * @param feature FeatureInterface; the feature to which this way belongs */ private void addWay(final Way way, final FeatureInterface feature) { List wayNodes = way.getWayNodes(); SerializablePath path = new SerializablePath(Path2D.WIND_NON_ZERO, wayNodes.size()); boolean start = false; for (WayNode wayNode : wayNodes) { float[] coordinate; if (wayNode.getNodeId() != 0) { Node node = this.nodes.get(wayNode.getNodeId()); coordinate = this.coordinateTransform.floatTransform(node.getLongitude(), node.getLatitude()); } else { coordinate = this.coordinateTransform.floatTransform(wayNode.getLongitude(), wayNode.getLatitude()); } if (!start) { path.moveTo(coordinate[0], coordinate[1]); start = true; } path.lineTo(coordinate[0], coordinate[1]); } String[] att = new String[0]; feature.getShapes().add(new GisObject(path, att)); } /** {@inheritDoc} */ @Override public void close() { // nothing to do right now. } }