Skip to content

Commit

Permalink
Merge pull request #720 from lat-lon/spatialJoins
Browse files Browse the repository at this point in the history
Enhanced deegree for support of Spatial Joins
  • Loading branch information
copierrj authored Nov 23, 2022
2 parents 1ae5301 + 0501801 commit 275ffa9
Show file tree
Hide file tree
Showing 56 changed files with 2,035 additions and 583 deletions.
Original file line number Diff line number Diff line change
@@ -0,0 +1,172 @@
//$HeadURL$
/*----------------------------------------------------------------------------
This file is part of deegree, http://deegree.org/
Copyright (C) 2001-2015 by:
- Department of Geography, University of Bonn -
and
- lat/lon GmbH -
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
Contact information:
lat/lon GmbH
Aennchenstr. 19, 53177 Bonn
Germany
http://lat-lon.de/
Department of Geography, University of Bonn
Prof. Dr. Klaus Greve
Postfach 1147, 53001 Bonn
Germany
http://www.geographie.uni-bonn.de/deegree/
e-mail: info@deegree.org
----------------------------------------------------------------------------*/
package org.deegree.feature;

import java.util.List;

import javax.xml.namespace.QName;

import org.deegree.commons.tom.TypedObjectNode;
import org.deegree.commons.tom.gml.property.Property;
import org.deegree.feature.property.ExtraProps;
import org.deegree.feature.types.FeatureType;
import org.deegree.geometry.Envelope;

/**
* Encapsulates a tuple of features as described in WFS 2.0 as result set for joins.
*
* @author <a href="mailto:goltz@lat-lon.de">Lyn Goltz</a>
*/
public class FeatureTuple implements Feature {

private final List<Feature> features;

private String id;

private Envelope envelope;

private boolean envelopeCalculated = false;

/**
* @param features
* list of features part of this tuple, never <code>null</code>
*/
public FeatureTuple( List<Feature> features ) {
this.features = features;
this.id = createId( features );
}

/**
* @return all features part of this tuple, never <code>null</code>
*/
public List<Feature> getTupleFeatures() {
return features;
}

@Override
public String getId() {
return id;
}

@Override
public List<Property> getProperties() {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public List<Property> getProperties( QName propName ) {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public void setId( String id ) {
this.id = id;
}

@Override
public QName getName() {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public FeatureType getType() {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public List<Property> getGeometryProperties() {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public Envelope getEnvelope() {
if ( !envelopeCalculated ) {
envelope = calcEnvelope();
}
return envelope;
}

@Override
public void setEnvelope( Envelope env ) {
this.envelope = env;
envelopeCalculated = true;
}

@Override
public Envelope calcEnvelope() {
Envelope fcBBox = null;
for ( Feature feature : this.features ) {
Envelope memberBBox = feature.getEnvelope();
if ( memberBBox != null ) {
if ( fcBBox != null ) {
fcBBox = fcBBox.merge( memberBBox );
} else {
fcBBox = memberBBox;
}
}
}
return fcBBox;
}

@Override
public void setPropertyValue( QName propName, int occurence, TypedObjectNode value ) {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public void setProperties( List<Property> props )
throws IllegalArgumentException {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public ExtraProps getExtraProperties() {
throw new UnsupportedOperationException( "Not implemented yet." );
}

@Override
public void setExtraProperties( ExtraProps extraProps ) {
throw new UnsupportedOperationException( "Not implemented yet." );
}

private String createId( List<Feature> features ) {
String id = "tupel_";
for ( Feature feature : features )
id += feature.getId();
return id;
}

}
Original file line number Diff line number Diff line change
Expand Up @@ -123,7 +123,8 @@ public class Filters {
* <p>
* The returned {@link Envelope} is determined by the following strategy:
* <ul>
* <li>If the filter is an {@link OperatorFilter}, it is attempted to extract an {@link BBOX} constraint from it.</li>
* <li>If the filter is an {@link OperatorFilter}, it is attempted to extract an {@link BBOX} constraint from it.
* </li>
* <li>If no {@link BBOX} constraint can be extracted from the filter (not presented or nested in <code>Or</code> or
* <code>Not</code> expressions, <code>null</code> is returned.</li>
* </ul>
Expand Down Expand Up @@ -190,25 +191,37 @@ private static BBOX extractBBox( SpatialOperator oper ) {
SubType type = oper.getSubType();
switch ( type ) {
case BBOX:
return (BBOX) oper;
if ( ( (BBOX) oper ).getGeometry() != null )
return (BBOX) oper;
return null;
case CONTAINS:
// Oracle does not like zero-extent bboxes
if ( !( ( (Contains) oper ).getGeometry() instanceof Point ) )
if ( ( (Contains) oper ).getGeometry() != null && !( ( (Contains) oper ).getGeometry() instanceof Point ) )
return new BBOX( ( (Contains) oper ).getParam1(), ( (Contains) oper ).getGeometry().getEnvelope() );
return null;
case CROSSES:
return new BBOX( ( (Crosses) oper ).getParam1(), ( (Crosses) oper ).getGeometry().getEnvelope() );
if ( ( (Crosses) oper ).getGeometry() != null )
return new BBOX( ( (Crosses) oper ).getParam1(), ( (Crosses) oper ).getGeometry().getEnvelope() );
return null;
case DWITHIN:
// TOOD use enlarged bbox
return null;
case EQUALS:
return new BBOX( ( (Equals) oper ).getParam1(), ( (Equals) oper ).getGeometry().getEnvelope() );
if ( ( (Equals) oper ).getGeometry() != null )
return new BBOX( ( (Equals) oper ).getParam1(), ( (Equals) oper ).getGeometry().getEnvelope() );
return null;
case INTERSECTS:
return new BBOX( ( (Intersects) oper ).getParam1(), ( (Intersects) oper ).getGeometry().getEnvelope() );
if ( ( (Intersects) oper ).getGeometry() != null )
return new BBOX( ( (Intersects) oper ).getParam1(), ( (Intersects) oper ).getGeometry().getEnvelope() );
return null;
case OVERLAPS:
return new BBOX( ( (Overlaps) oper ).getParam1(), ( (Overlaps) oper ).getGeometry().getEnvelope() );
if ( ( (Overlaps) oper ).getGeometry() != null )
return new BBOX( ( (Overlaps) oper ).getParam1(), ( (Overlaps) oper ).getGeometry().getEnvelope() );
return null;
case WITHIN:
return new BBOX( ( (Within) oper ).getParam1(), ( (Within) oper ).getGeometry().getEnvelope() );
if ( ( (Within) oper ).getGeometry() != null )
return new BBOX( ( (Within) oper ).getParam1(), ( (Within) oper ).getGeometry().getEnvelope() );
return null;
default: {
return null;
}
Expand Down Expand Up @@ -450,33 +463,33 @@ public static Expression repair( Expression e, Map<String, QName> bindings, Set<
switch ( e.getType() ) {
case ADD:
Add a = (Add) e;
return new Add( repair( a.getParameter1(), bindings, validNames ), repair( a.getParameter2(), bindings,
validNames ) );
return new Add( repair( a.getParameter1(), bindings, validNames ),
repair( a.getParameter2(), bindings, validNames ) );
case CUSTOM:
return e;
case DIV:
Div d = (Div) e;
return new Div( repair( d.getParameter1(), bindings, validNames ), repair( d.getParameter2(), bindings,
validNames ) );
return new Div( repair( d.getParameter1(), bindings, validNames ),
repair( d.getParameter2(), bindings, validNames ) );
case FUNCTION:
// workaround seems to produce errors, so function expressions are not fixed now
return e;
// Function f = (Function) e;
// List<Expression> ps = new ArrayList<Expression>();
// for ( Expression ex : f.getParameters() ) {
// ps.add( repair( ex, bindings, validNames ) );
// }
// return new Function( f.getName(), ps );
// Function f = (Function) e;
// List<Expression> ps = new ArrayList<Expression>();
// for ( Expression ex : f.getParameters() ) {
// ps.add( repair( ex, bindings, validNames ) );
// }
// return new Function( f.getName(), ps );
case LITERAL:
return e;
case MUL:
Mul m = (Mul) e;
return new Mul( repair( m.getParameter1(), bindings, validNames ), repair( m.getParameter2(), bindings,
validNames ) );
return new Mul( repair( m.getParameter1(), bindings, validNames ),
repair( m.getParameter2(), bindings, validNames ) );
case SUB:
Sub s = (Sub) e;
return new Sub( repair( s.getParameter1(), bindings, validNames ), repair( s.getParameter2(), bindings,
validNames ) );
return new Sub( repair( s.getParameter1(), bindings, validNames ),
repair( s.getParameter2(), bindings, validNames ) );
case VALUE_REFERENCE:
ValueReference vr = (ValueReference) e;
QName name = vr.getAsQName();
Expand All @@ -494,7 +507,8 @@ public static Expression repair( Expression e, Map<String, QName> bindings, Set<
return e;
}

private static ComparisonOperator repair( ComparisonOperator o, Map<String, QName> bindings, Set<QName> validNames ) {
private static ComparisonOperator repair( ComparisonOperator o, Map<String, QName> bindings,
Set<QName> validNames ) {
Expression[] exs = o.getParams();
for ( int i = 0; i < exs.length; ++i ) {
exs[i] = repair( exs[i], bindings, validNames );
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -68,8 +68,6 @@ public class BBOX extends SpatialOperator {

private static final Logger LOG = LoggerFactory.getLogger( BBOX.class );

private final Envelope param2;

private final boolean allowFalsePositives;

/**
Expand All @@ -94,6 +92,18 @@ public BBOX( Expression param1, Envelope param2 ) {
this( param1, param2, false );
}

/**
* Creates a new {@link BBOX} instance which uses the specified geometry property and bounding box.
*
* @param param1
* geometry to compare to, can be <code>null</code> (use default geometry)
* @param param2
* bounding box argument for intersection testing, never <code>null</code>
*/
public BBOX( Expression param1, ValueReference param2 ) {
this( param1, param2, false );
}

/**
* Creates a new {@link BBOX} instance which uses the specified geometry property and bounding box.
*
Expand All @@ -105,8 +115,22 @@ public BBOX( Expression param1, Envelope param2 ) {
* set to <code>true</code>, if false positives are acceptable (may enable faster index-only checks)
*/
public BBOX( final Expression param1, final Envelope param2, final boolean allowFalsePositives ) {
super( param1 );
this.param2 = param2;
super( param1, param2 );
this.allowFalsePositives = allowFalsePositives;
}

/**
* Creates a new {@link BBOX} instance which uses the specified geometry property and bounding box.
*
* @param param1
* geometry to compare to, can be <code>null</code> (use default geometry)
* @param param2
* bounding box argument for intersection testing, never <code>null</code>
* @param allowFalsePositives
* set to <code>true</code>, if false positives are acceptable (may enable faster index-only checks)
*/
public BBOX( final Expression param1, final ValueReference param2, final boolean allowFalsePositives ) {
super( param1, param2 );
this.allowFalsePositives = allowFalsePositives;
}

Expand All @@ -119,7 +143,7 @@ public BBOX( final Expression param1, final Envelope param2, final boolean allow
*/
@Override
public ValueReference getPropName() {
return (ValueReference) propName;
return (ValueReference) param1;
}

/**
Expand All @@ -128,7 +152,7 @@ public ValueReference getPropName() {
* @return the envelope, never <code>null</code>
*/
public Envelope getBoundingBox() {
return param2;
return (Envelope) param2AsGeometry;
}

/**
Expand All @@ -149,7 +173,7 @@ public <T> boolean evaluate( T obj, XPathEvaluator<T> xpathEvaluator )
for ( TypedObjectNode paramValue : param1.evaluate( obj, xpathEvaluator ) ) {
Geometry param1Value = checkGeometryOrNull( paramValue );
if ( param1Value != null ) {
Envelope transformedBBox = (Envelope) getCompatibleGeometry( param1Value, param2 );
Envelope transformedBBox = (Envelope) getCompatibleGeometry( param1Value, getBoundingBox() );
return transformedBBox.intersects( param1Value );
}
}
Expand All @@ -158,7 +182,7 @@ public <T> boolean evaluate( T obj, XPathEvaluator<T> xpathEvaluator )
Feature f = (Feature) obj;
Envelope env = f.getEnvelope();
if ( env != null ) {
Envelope transformedBBox = (Envelope) getCompatibleGeometry( env, param2 );
Envelope transformedBBox = (Envelope) getCompatibleGeometry( env, getBoundingBox() );
return transformedBBox.intersects( env );
}
} else {
Expand All @@ -170,13 +194,18 @@ public <T> boolean evaluate( T obj, XPathEvaluator<T> xpathEvaluator )
@Override
public String toString( String indent ) {
String s = indent + "-BBOX\n";
s += indent + propName + "\n";
s += indent + param2;
s += indent + param1 + "\n";
if ( param2AsGeometry != null )
s += indent + param2AsGeometry;
if ( param2AsValueReference != null )
s += indent + param2AsValueReference;
return s;
}

@Override
public Object[] getParams() {
return new Object[] { propName, param2 };
if ( param2AsValueReference != null )
return new Object[] { param1, param2AsValueReference };
return new Object[] { param1, param2AsGeometry };
}
}
Loading

0 comments on commit 275ffa9

Please sign in to comment.