com.vividsolutions.jts.operation.predicate.RectangleIntersects Maven / Gradle / Ivy
/*
* The JTS Topology Suite is a collection of Java classes that
* implement the fundamental operations required to validate a given
* geo-spatial data set to a known topological specification.
*
* Copyright (C) 2001 Vivid Solutions
*
* This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public
* License as published by the Free Software Foundation; either
* version 2.1 of the License, or (at your option) any later version.
*
* This library is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
* Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the Free Software
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
*
* For more information, contact:
*
* Vivid Solutions
* Suite #1A
* 2328 Government Street
* Victoria BC V8T 5G5
* Canada
*
* (250)385-6040
* www.vividsolutions.com
*/
package com.vividsolutions.jts.operation.predicate;
import java.util.*;
import com.vividsolutions.jts.geom.*;
import com.vividsolutions.jts.algorithm.*;
import com.vividsolutions.jts.algorithm.locate.SimplePointInAreaLocator;
import com.vividsolutions.jts.geom.util.*;
/**
* Implementation of the intersects spatial predicate
* optimized for the case where one {@link Geometry} is a rectangle.
* This class works for all
* input geometries, including {@link GeometryCollection}s.
*
* As a further optimization,
* this class can be used in batch style
* to test many geometries
* against a single rectangle.
*
* @version 1.7
*/
public class RectangleIntersects
{
/**
* Tests whether a rectangle intersects a given geometry.
*
* @param rectangle
* a rectangular Polygon
* @param b
* a Geometry of any type
* @return true if the geometries intersect
*/
public static boolean intersects(Polygon rectangle, Geometry b)
{
RectangleIntersects rp = new RectangleIntersects(rectangle);
return rp.intersects(b);
}
private Polygon rectangle;
private Envelope rectEnv;
/**
* Create a new intersects computer for a rectangle.
*
* @param rectangle
* a rectangular Polygon
*/
public RectangleIntersects(Polygon rectangle)
{
this.rectangle = rectangle;
rectEnv = rectangle.getEnvelopeInternal();
}
/**
* Tests whether the given Geometry intersects
* the query rectangle.
*
* @param geom the Geometry to test (may be of any type)
* @return true if the geometry intersects the query rectangle
*/
public boolean intersects(Geometry geom)
{
if (!rectEnv.intersects(geom.getEnvelopeInternal()))
return false;
/**
* Test if rectangle envelope intersects any component envelope.
* This handles Point components as well
*/
EnvelopeIntersectsVisitor visitor = new EnvelopeIntersectsVisitor(rectEnv);
visitor.applyTo(geom);
if (visitor.intersects())
return true;
/**
* Test if any rectangle vertex is contained in the target geometry
*/
GeometryContainsPointVisitor ecpVisitor = new GeometryContainsPointVisitor(rectangle);
ecpVisitor.applyTo(geom);
if (ecpVisitor.containsPoint())
return true;
/**
* Test if any target geometry line segment intersects the rectangle
*/
RectangleIntersectsSegmentVisitor riVisitor = new RectangleIntersectsSegmentVisitor(rectangle);
riVisitor.applyTo(geom);
if (riVisitor.intersects())
return true;
return false;
}
}
/**
* Tests whether it can be concluded that a rectangle intersects a geometry,
* based on the relationship of the envelope(s) of the geometry.
*
* @author Martin Davis
* @version 1.7
*/
class EnvelopeIntersectsVisitor extends ShortCircuitedGeometryVisitor
{
private Envelope rectEnv;
private boolean intersects = false;
public EnvelopeIntersectsVisitor(Envelope rectEnv)
{
this.rectEnv = rectEnv;
}
/**
* Reports whether it can be concluded that an intersection occurs,
* or whether further testing is required.
*
* @return true if an intersection must occur
* or false if no conclusion about intersection can be made
*/
public boolean intersects()
{
return intersects;
}
protected void visit(Geometry element)
{
Envelope elementEnv = element.getEnvelopeInternal();
// disjoint => no intersection
if (!rectEnv.intersects(elementEnv)) {
return;
}
// rectangle contains target env => must intersect
if (rectEnv.contains(elementEnv)) {
intersects = true;
return;
}
/**
* Since the envelopes intersect and the test element is connected, if the
* test envelope is completely bisected by an edge of the rectangle the
* element and the rectangle must touch (This is basically an application of
* the Jordan Curve Theorem). The alternative situation is that the test
* envelope is "on a corner" of the rectangle envelope, i.e. is not
* completely bisected. In this case it is not possible to make a conclusion
* about the presence of an intersection.
*/
if (elementEnv.getMinX() >= rectEnv.getMinX()
&& elementEnv.getMaxX() <= rectEnv.getMaxX()) {
intersects = true;
return;
}
if (elementEnv.getMinY() >= rectEnv.getMinY()
&& elementEnv.getMaxY() <= rectEnv.getMaxY()) {
intersects = true;
return;
}
}
protected boolean isDone()
{
return intersects == true;
}
}
/**
* A visitor which tests whether it can be
* concluded that a geometry contains a vertex of
* a query geometry.
*
* @author Martin Davis
* @version 1.7
*/
class GeometryContainsPointVisitor extends ShortCircuitedGeometryVisitor
{
private CoordinateSequence rectSeq;
private Envelope rectEnv;
private boolean containsPoint = false;
public GeometryContainsPointVisitor(Polygon rectangle)
{
this.rectSeq = rectangle.getExteriorRing().getCoordinateSequence();
rectEnv = rectangle.getEnvelopeInternal();
}
/**
* Reports whether it can be concluded that a corner point of the rectangle is
* contained in the geometry, or whether further testing is required.
*
* @return true if a corner point is contained
* or false if no conclusion about intersection can be made
*/
public boolean containsPoint()
{
return containsPoint;
}
protected void visit(Geometry geom)
{
// if test geometry is not polygonal this check is not needed
if (!(geom instanceof Polygon))
return;
// skip if envelopes do not intersect
Envelope elementEnv = geom.getEnvelopeInternal();
if (!rectEnv.intersects(elementEnv))
return;
// test each corner of rectangle for inclusion
Coordinate rectPt = new Coordinate();
for (int i = 0; i < 4; i++) {
rectSeq.getCoordinate(i, rectPt);
if (!elementEnv.contains(rectPt))
continue;
// check rect point in poly (rect is known not to touch polygon at this
// point)
if (SimplePointInAreaLocator.containsPointInPolygon(rectPt,
(Polygon) geom)) {
containsPoint = true;
return;
}
}
}
protected boolean isDone()
{
return containsPoint == true;
}
}
/**
* A visitor to test for intersection between the query
* rectangle and the line segments of the geometry.
*
* @author Martin Davis
*
*/
class RectangleIntersectsSegmentVisitor extends ShortCircuitedGeometryVisitor
{
private Envelope rectEnv;
private RectangleLineIntersector rectIntersector;
private boolean hasIntersection = false;
private Coordinate p0 = new Coordinate();
private Coordinate p1 = new Coordinate();
/**
* Creates a visitor for checking rectangle intersection
* with segments
*
* @param rectangle the query rectangle
*/
public RectangleIntersectsSegmentVisitor(Polygon rectangle)
{
rectEnv = rectangle.getEnvelopeInternal();
rectIntersector = new RectangleLineIntersector(rectEnv);
}
/**
* Reports whether any segment intersection exists.
*
* @return true if a segment intersection exists
* or false if no segment intersection exists
*/
public boolean intersects()
{
return hasIntersection;
}
protected void visit(Geometry geom)
{
/**
* It may be the case that the rectangle and the
* envelope of the geometry component are disjoint,
* so it is worth checking this simple condition.
*/
Envelope elementEnv = geom.getEnvelopeInternal();
if (!rectEnv.intersects(elementEnv))
return;
// check segment intersections
// get all lines from geometry component
// (there may be more than one if it's a multi-ring polygon)
List lines = LinearComponentExtracter.getLines(geom);
checkIntersectionWithLineStrings(lines);
}
private void checkIntersectionWithLineStrings(List lines)
{
for (Iterator i = lines.iterator(); i.hasNext(); ) {
LineString testLine = (LineString) i.next();
checkIntersectionWithSegments(testLine);
if (hasIntersection)
return;
}
}
private void checkIntersectionWithSegments(LineString testLine)
{
CoordinateSequence seq1 = testLine.getCoordinateSequence();
for (int j = 1; j < seq1.size(); j++) {
seq1.getCoordinate(j - 1, p0);
seq1.getCoordinate(j, p1);
if (rectIntersector.intersects(p0, p1)) {
hasIntersection = true;
return;
}
}
}
protected boolean isDone()
{
return hasIntersection == true;
}
}