// This software is released into the Public Domain. See copying.txt for details.
package org.openstreetmap.osmosis.areafilter.v0_6;
import org.openstreetmap.osmosis.core.container.v0_6.BoundContainer;
import org.openstreetmap.osmosis.core.domain.v0_6.Bound;
import org.openstreetmap.osmosis.core.domain.v0_6.Node;
import org.openstreetmap.osmosis.core.filter.common.IdTrackerType;
/**
* Provides a filter for extracting all entities that lie within a specific geographical box
* identified by latitude and longitude coordinates.
*
* @author Brett Henderson
*/
public class BoundingBoxFilter extends AreaFilter {
private Bound bound; // use a Bound for the internal representation
/**
* Creates a new instance with the specified geographical coordinates. When filtering, nodes
* right on the edge of the box will be included.
*
* @param idTrackerType
* Defines the id tracker implementation to use.
* @param left
* The longitude marking the left edge of the bounding box.
* @param right
* The longitude marking the right edge of the bounding box.
* @param top
* The latitude marking the top edge of the bounding box.
* @param bottom
* The latitude marking the bottom edge of the bounding box.
* @param clipIncompleteEntities
* If true, entities referring to non-existent entities will be
* modified to ensure referential integrity. For example, ways
* will be modified to only include nodes inside the area.
* @param completeWays
* Include all nodes for ways which have at least one node inside the filtered area.
* @param completeRelations
* Include all relations referenced by other relations which have members inside the
* filtered area.
* @param cascadingRelations
* Include all relations that reference other relations which have members inside the
* filtered area. This is less costly than completeRelations.
*/
public BoundingBoxFilter(IdTrackerType idTrackerType,
double left,
double right,
double top,
double bottom,
boolean clipIncompleteEntities,
boolean completeWays,
boolean completeRelations,
boolean cascadingRelations) {
super(idTrackerType, clipIncompleteEntities, completeWays, completeRelations, cascadingRelations);
this.bound = new Bound(right, left, top, bottom, "");
}
/**
* {@inheritDoc}
*/
@Override
public void process(BoundContainer boundContainer) {
Bound newBound;
/*
* The order of calling intersect is important because the first non-empty origin string
* will be used for the resulting Bound, and we want the origin string from the pipeline
* Bound to be used.
*/
newBound = boundContainer.getEntity().intersect(bound);
// intersect will return null if there is no overlapping area
if (newBound != null) {
// Send on a bound element clipped to the area
super.process(new BoundContainer(newBound));
}
}
/**
* {@inheritDoc}
*/
@Override
protected boolean isNodeWithinArea(Node node) {
double latitude;
double longitude;
latitude = node.getLatitude();
longitude = node.getLongitude();
/*
* Check the node coordinates against the bounding box by comparing them to each "simple"
* bound.
*/
for (Bound b : bound.toSimpleBound()) {
if (b.getTop() >= latitude
&& b.getBottom() <= latitude
&& b.getLeft() <= longitude
&& b.getRight() >= longitude) {
return true;
}
}
return false;
}
}