Package org.openstreetmap.osmosis.dataset.v0_6.impl

Source Code of org.openstreetmap.osmosis.dataset.v0_6.impl.DatasetStoreReader$ResultIterator

// This software is released into the Public Domain.  See copying.txt for details.
package org.openstreetmap.osmosis.dataset.v0_6.impl;

import java.awt.geom.Rectangle2D;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.logging.Level;
import java.util.logging.Logger;

import org.openstreetmap.osmosis.core.container.v0_6.DatasetContext;
import org.openstreetmap.osmosis.core.container.v0_6.EntityContainer;
import org.openstreetmap.osmosis.core.container.v0_6.EntityManager;
import org.openstreetmap.osmosis.core.container.v0_6.NodeContainer;
import org.openstreetmap.osmosis.core.container.v0_6.NodeContainerIterator;
import org.openstreetmap.osmosis.core.container.v0_6.RelationContainer;
import org.openstreetmap.osmosis.core.container.v0_6.RelationContainerIterator;
import org.openstreetmap.osmosis.core.container.v0_6.WayContainer;
import org.openstreetmap.osmosis.core.container.v0_6.WayContainerIterator;
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.Way;
import org.openstreetmap.osmosis.core.domain.v0_6.WayNode;
import org.openstreetmap.osmosis.core.filter.common.DynamicIdTracker;
import org.openstreetmap.osmosis.core.filter.common.IdTracker;
import org.openstreetmap.osmosis.core.lifecycle.ReleasableIterator;
import org.openstreetmap.osmosis.core.store.EmptyIterator;
import org.openstreetmap.osmosis.core.store.MultipleSourceIterator;
import org.openstreetmap.osmosis.core.store.NoSuchIndexElementException;
import org.openstreetmap.osmosis.core.store.ReleasableAdaptorForIterator;
import org.openstreetmap.osmosis.core.store.UpcastIterator;


/**
* Provides read-only access to a dataset store. Each thread accessing the store
* must create its own reader. The reader maintains all references to
* heavyweight resources such as file handles used to access the store
* eliminating the need for objects such as object iterators to be cleaned up
* explicitly.
*
* @author Brett Henderson
*/
public class DatasetStoreReader implements DatasetContext {
 
  private static final Logger LOG = Logger.getLogger(DatasetStoreReader.class.getName());
 
  private NodeStorageContainer nodeStorageContainer;
  private WayStorageContainer wayStorageContainer;
  private RelationStorageContainer relationStorageContainer;
  private NodeManager nodeManager;
  private WayManager wayManager;
  private RelationManager relationManager;
 
  private boolean enableWayTileIndex;
 
 
  /**
   * Creates a new instance.
   *
   * @param nodeStorageContainer
   *            The node storages.
   * @param wayStorageContainer
   *            The way storages.
   * @param relationStorageContainer
   *            The relation storages.
   * @param enableWayTileIndex
   *            If true a tile index is created for ways, otherwise a node-way
   *            index is used.
   */
  public DatasetStoreReader(
      NodeStorageContainer nodeStorageContainer,
      WayStorageContainer wayStorageContainer,
      RelationStorageContainer relationStorageContainer,
      boolean enableWayTileIndex) {
    this.nodeStorageContainer = nodeStorageContainer;
    this.wayStorageContainer = wayStorageContainer;
    this.relationStorageContainer = relationStorageContainer;
   
    this.enableWayTileIndex = enableWayTileIndex;
   
    nodeManager = new NodeManager(nodeStorageContainer);
    wayManager = new WayManager(wayStorageContainer);
    relationManager = new RelationManager(relationStorageContainer);
  }
 
 
  /**
   * {@inheritDoc}
   */
  private ReleasableIterator<Long> getNodeIdsForTileRange(int minimumTile, int maximumTile) {
    return new TileIndexValueIdIterator(
        nodeStorageContainer.getNodeTileIndexReader().getRange(minimumTile, maximumTile));
  }
 
 
  /**
   * {@inheritDoc}
   */
  private ReleasableIterator<Long> getWayIdsForTileRange(int minimumTile, int maximumTile) {
    return new ReleasableAdaptorForIterator<Long>(
        wayStorageContainer.getWayTileIndexReader().getRange(minimumTile, maximumTile));
  }
 
 
  /**
   * {@inheritDoc}
   */
  private ReleasableIterator<Long> getWayIdsOwningNode(long nodeId) {
    return new RelationalIndexValueIdIterator(
        nodeStorageContainer.getNodeWayIndexReader().getRange(nodeId, nodeId));
  }
 
 
  /**
   * {@inheritDoc}
   */
  private ReleasableIterator<Long> getRelationIdsOwningNode(long nodeId) {
    return new RelationalIndexValueIdIterator(
        nodeStorageContainer.getNodeRelationIndexReader().getRange(nodeId, nodeId));
  }
 
 
  /**
   * {@inheritDoc}
   */
  private ReleasableIterator<Long> getRelationIdsOwningWay(long wayId) {
    return new RelationalIndexValueIdIterator(
        wayStorageContainer.getWayRelationIndexReader().getRange(wayId, wayId));
  }
 
 
  /**
   * {@inheritDoc}
   */
  private ReleasableIterator<Long> getRelationIdsOwningRelation(long relationId) {
    return new RelationalIndexValueIdIterator(
        relationStorageContainer.getRelationRelationIndexReader().getRange(relationId, relationId));
  }
 
 
  /**
   * {@inheritDoc}
   */
  private boolean isTileWayIndexAvailable() {
    return enableWayTileIndex;
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  @Deprecated
  public Node getNode(long id) {
    return nodeManager.getEntity(id);
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  @Deprecated
  public Way getWay(long id) {
    return wayManager.getEntity(id);
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  @Deprecated
  public Relation getRelation(long id) {
    return relationManager.getEntity(id);
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  public EntityManager<Node> getNodeManager() {
    return nodeManager;
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public EntityManager<Way> getWayManager() {
    return wayManager;
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public EntityManager<Relation> getRelationManager() {
    return relationManager;
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  public ReleasableIterator<EntityContainer> iterate() {
    List<ReleasableIterator<EntityContainer>> sources;
   
    sources = new ArrayList<ReleasableIterator<EntityContainer>>();
   
    sources.add(
        new UpcastIterator<EntityContainer, NodeContainer>(
            new NodeContainerIterator(nodeManager.iterate())));
    sources.add(
        new UpcastIterator<EntityContainer, WayContainer>(
            new WayContainerIterator(wayManager.iterate())));
    sources.add(
        new UpcastIterator<EntityContainer, RelationContainer>(
            new RelationContainerIterator(relationManager.iterate())));
   
    return new MultipleSourceIterator<EntityContainer>(sources);
  }
 
 
  /**
   * Determines if a node lies within the bounding box.
   *
   * @param boundingBox
   *            The bounding box.
   * @param node
   *            The node to be checked.
   * @return True if the node lies within the box.
   */
  private boolean isNodeInsideBox(Rectangle2D boundingBox, Node node) {
    return boundingBox.contains(node.getLongitude(), node.getLatitude());
  }
 
 
  /**
   * Determines if a way lies within the bounding box.
   *
   * @param boundingBox
   *            The bounding box.
   * @param nodes
   *            The ordered nodes of the way in order.
   * @return True if the way is at least partially within the box.
   */
  private boolean isWayInsideBox(Rectangle2D boundingBox, List<Node> nodes) {
    // If at least one node lies within the box, the way is inside the box.
    for (Node node : nodes) {
      if (isNodeInsideBox(boundingBox, node)) {
        return true;
      }
    }
   
    // Now we need to check if any of the segments cross the box.
    for (int i = 0; i < nodes.size() - 1; i++) {
      Node nodeA;
      Node nodeB;
     
      nodeA = nodes.get(i);
      nodeB = nodes.get(i + 1);
     
      if (boundingBox.intersectsLine(nodeA.getLongitude(), nodeA.getLatitude(), nodeB.getLongitude(),
          nodeB.getLatitude())) {
        return true;
      }
    }
   
    return false;
  }
 
 
  /**
   * Retrieves all nodes for the bounding box and populates the node id
   * tracker.
   *
   * @param bboxCtx
   *            The bounding box data.
   */
  private void populateNodeIds(BoundingBoxContext bboxCtx) {
    ReleasableIterator<Long> nodeIdsForTileset;
    IdTracker idTracker;
   
    idTracker = new DynamicIdTracker();
   
    // Search through all nodes in the tile range and add them to a
    // temporary id tracker. This temporary id tracker allows all node ids
    // to be sorted ascendingly prior to retrieving the nodes themselves
    // which improves index performance.
    nodeIdsForTileset = getNodeIdsForTileRange(bboxCtx.minimumTile, bboxCtx.maximumTile);
    try {
      while (nodeIdsForTileset.hasNext()) {
        idTracker.set(nodeIdsForTileset.next());
      }
     
    } finally {
      nodeIdsForTileset.release();
    }
   
    // Check to see whether each applicable node lies within the bounding
    // box and add them to the result id list if they are.
    for (long nodeId : idTracker) {
      Node node = getNode(nodeId);
     
      // Determine if the node lies within the required bounding box.
      if (isNodeInsideBox(bboxCtx.boundingBox, node)) {
        bboxCtx.nodeIdTracker.set(nodeId);
      }
    }
  }
 
 
  /**
   * Retrieves all ways for the bounding box, populates the way id tracker,
   * and updates the external node tracker with any nodes outside the box if
   * complete ways are required.
   *
   * @param bboxCtx
   *            The bounding box data.
   */
  private void populateWayIdsUsingTileWayIndex(BoundingBoxContext bboxCtx, boolean completeWays) {
    ReleasableIterator<Long> tileWayIndexValues;
   
    // Search through all ways in the tile range and store the ids of those
    // within the bounding box.
    tileWayIndexValues = getWayIdsForTileRange(bboxCtx.minimumTile, bboxCtx.maximumTile);
    try {
      while (tileWayIndexValues.hasNext()) {
        long wayId;
        Way way;
        List<Node> nodes;
       
        // Load the current way.
        wayId = tileWayIndexValues.next();
        way = getWay(wayId);
       
        // Load the nodes within the way.
        nodes = new ArrayList<Node>();
        for (WayNode wayNode : way.getWayNodes()) {
          try {
            nodes.add(getNode(wayNode.getNodeId()));
          } catch (NoSuchIndexElementException e) {
            // Ignore any referential integrity problems.
            if (LOG.isLoggable(Level.FINER)) {
              LOG.finest(
                "Ignoring referential integrity problem where way " + wayId
                + " refers to non-existent node " + wayNode.getNodeId() + "."
              );
            }
          }
        }
       
        // Determine if the way lies within the required bounding box.
        if (isWayInsideBox(bboxCtx.boundingBox, nodes)) {
          bboxCtx.wayIdTracker.set(wayId);
         
          // If we want complete ways, we need to check the list of nodes
          // adding any nodes that haven't already been selected (ie.
          // those that are outside the box).
          if (completeWays) {
            for (WayNode wayNode : way.getWayNodes()) {
              long nodeId;
             
              nodeId = wayNode.getNodeId();
             
              if (!bboxCtx.nodeIdTracker.get(nodeId)) {
                bboxCtx.externalNodeIdTracker.set(nodeId);
              }
            }
          }
        }
      }
    } finally {
      tileWayIndexValues.release();
    }
  }
 
 
  /**
   * Retrieves all ways for the currently selected nodes, populates the way id
   * tracker, and updates the external node tracker with any nodes outside the
   * box if complete ways are required.
   *
   * @param bboxCtx
   *            The bounding box data.
   */
  private void populateWayIdsUsingNodeWayIndex(BoundingBoxContext bboxCtx, boolean completeWays) {
    // Select all ways that contain the currently selected nodes.
    for (Long nodeId : bboxCtx.nodeIdTracker) {
      ReleasableIterator<Long> wayIdIterator = getWayIdsOwningNode(nodeId);
      try {
        while (wayIdIterator.hasNext()) {
          bboxCtx.wayIdTracker.set(wayIdIterator.next());
        }
       
      } finally {
        wayIdIterator.release();
      }
    }
   
    // If we want complete ways, we need to load each way and
    // check the list of nodes adding any nodes that haven't
    // already been selected (ie. those that are outside the box).
    // This is done outside the main loop so that ways are loaded
    // in ascending order which utilises index caching more effectively
    if (completeWays) {
      for (Long wayId : bboxCtx.wayIdTracker) {
        Way way;
       
        way = getWay(wayId);
       
        for (WayNode wayNode : way.getWayNodes()) {
          long externalNodeId;
         
          externalNodeId = wayNode.getNodeId();
         
          if (!bboxCtx.nodeIdTracker.get(externalNodeId)) {
            bboxCtx.externalNodeIdTracker.set(externalNodeId);
          }
        }
      }
    }
  }
 
 
  /**
   * Retrieves all relations for the currently selected nodes and ways,
   * populates the relation id tracker, and recursively includes all parents
   * of selected relations.
   *
   * @param bboxCtx
   *            The bounding box data.
   */
  private void populateRelationIds(BoundingBoxContext bboxCtx) {
    // Select all relations that contain the currently selected nodes, ways and relations.
    for (Long nodeId : bboxCtx.nodeIdTracker) {
      ReleasableIterator<Long> relationIdIterator = getRelationIdsOwningNode(nodeId);
      try {
        while (relationIdIterator.hasNext()) {
          bboxCtx.relationIdTracker.set(relationIdIterator.next());
        }
       
      } finally {
        relationIdIterator.release();
      }
    }
    for (Long wayId : bboxCtx.wayIdTracker) {
      ReleasableIterator<Long> relationIdIterator = getRelationIdsOwningWay(wayId);
      try {
        while (relationIdIterator.hasNext()) {
          bboxCtx.relationIdTracker.set(relationIdIterator.next());
        }
       
      } finally {
        relationIdIterator.release();
      }
    }
    for (boolean moreParents = true; moreParents;) {
      // If parents of current relations are found, this flag will be set
      // triggering another round of searching.
      moreParents = false;
     
      for (Long relationId : bboxCtx.relationIdTracker) {
        ReleasableIterator<Long> relationIdIterator = getRelationIdsOwningRelation(relationId);
        try {
          while (relationIdIterator.hasNext()) {
            long parentRelationId;
           
            parentRelationId = relationIdIterator.next();
           
            if (!bboxCtx.relationIdTracker.get(parentRelationId)) {
              bboxCtx.relationIdTracker.set(parentRelationId);
              moreParents = true;
            }
          }
         
        } finally {
          relationIdIterator.release();
        }
      }
    }
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  public ReleasableIterator<EntityContainer> iterateBoundingBox(
      double left, double right, double top, double bottom, boolean completeWays) {
    BoundingBoxContext bboxCtx;
   
    LOG.fine("Beginning bounding box iteration.");
   
    // Create the bounding box context to manage the data associated with
    // this call.
    bboxCtx = new BoundingBoxContext(left, right, top, bottom);
   
    // Verify that the input coordinates create a positive box, if not just
    // return an empty result set.
    if (left > right || bottom > top) {
      LOG.fine("Bounding box is zero size, returning an empty iterator.");
      return new EmptyIterator<EntityContainer>();
    }
   
    LOG.fine("Populating node ids.");
    populateNodeIds(bboxCtx);
   
    if (isTileWayIndexAvailable()) {
      LOG.fine("Populating way ids using tile-way index.");
      populateWayIdsUsingTileWayIndex(bboxCtx, completeWays);
    } else {
      LOG.fine("Populating way ids using node-way index.");
      populateWayIdsUsingNodeWayIndex(bboxCtx, completeWays);
    }
   
    LOG.fine("Populating relation ids.");
    populateRelationIds(bboxCtx);
   
    // Now we need to add any external nodes that might have been included outside the bounding box.
    bboxCtx.nodeIdTracker.setAll(bboxCtx.externalNodeIdTracker);
   
    LOG.fine("Iterating all entities matching result ids.");
    return new ResultIterator(bboxCtx.nodeIdTracker, bboxCtx.wayIdTracker, bboxCtx.relationIdTracker);
  }
 
 
  /**
   * Returns a complete result set of matching records based on lists of
   * entity ids. It will return the nodes, followed by the ways, followed by
   * the relations.
   *
   * @author Brett Henderson
   */
  private class ResultIterator implements ReleasableIterator<EntityContainer> {
    private Iterator<Long> nodeIds;
    private Iterator<Long> wayIds;
    private Iterator<Long> relationIds;
   
   
    /**
     * Creates a new instance.
     *
     * @param nodeIdList
     *            The set of nodes to be returned.
     * @param wayIdList
     *            The set of ways to be returned.
     * @param relationIdList
     *            The set of relations to be returned.
     */
    public ResultIterator(IdTracker nodeIdList, IdTracker wayIdList, IdTracker relationIdList) {
      nodeIds = nodeIdList.iterator();
      wayIds = wayIdList.iterator();
      relationIds = relationIdList.iterator();
    }
   
   
    /**
     * {@inheritDoc}
     */
    @Override
    public boolean hasNext() {
      return (nodeIds.hasNext() || wayIds.hasNext() || relationIds.hasNext());
    }
   
   
    /**
     * {@inheritDoc}
     */
    @Override
    public EntityContainer next() {
      if (nodeIds.hasNext()) {
        return new NodeContainer(getNode(nodeIds.next()));
      }
      if (wayIds.hasNext()) {
        return new WayContainer(getWay(wayIds.next()));
      }
      if (relationIds.hasNext()) {
        return new RelationContainer(getRelation(relationIds.next()));
      }
     
      throw new NoSuchElementException();
    }
   
   
    /**
     * {@inheritDoc}
     */
    @Override
    public void remove() {
      throw new UnsupportedOperationException();
    }
   
   
    /**
     * {@inheritDoc}
     */
    @Override
    public void release() {
      // Do nothing.
    }
  }


  /**
   * {@inheritDoc}
   */
  @Override
  public void complete() {
    // This dataset is read-only so no changes need to be committed.
  }
 
 
  /**
   * {@inheritDoc}
   */
  @Override
  public void release() {
    nodeStorageContainer.release();
    wayStorageContainer.release();
    relationStorageContainer.release();
  }
}
TOP

Related Classes of org.openstreetmap.osmosis.dataset.v0_6.impl.DatasetStoreReader$ResultIterator

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.