Package org.geotools.caching.util

Source Code of org.geotools.caching.util.BBoxFilterSplitter

/*
*    GeoTools - The Open Source Java GIS Toolkit
*    http://geotools.org
*
*    (C) 2007-2008, Open Source Geospatial Foundation (OSGeo)
*
*    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;
*    version 2.1 of the License.
*
*    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.
*/
package org.geotools.caching.util;

import java.util.Iterator;
import java.util.Stack;

import org.geotools.factory.CommonFactoryFinder;
import org.opengis.filter.And;
import org.opengis.filter.ExcludeFilter;
import org.opengis.filter.Filter;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.FilterVisitor;
import org.opengis.filter.Id;
import org.opengis.filter.IncludeFilter;
import org.opengis.filter.Not;
import org.opengis.filter.Or;
import org.opengis.filter.PropertyIsBetween;
import org.opengis.filter.PropertyIsEqualTo;
import org.opengis.filter.PropertyIsGreaterThan;
import org.opengis.filter.PropertyIsGreaterThanOrEqualTo;
import org.opengis.filter.PropertyIsLessThan;
import org.opengis.filter.PropertyIsLessThanOrEqualTo;
import org.opengis.filter.PropertyIsLike;
import org.opengis.filter.PropertyIsNil;
import org.opengis.filter.PropertyIsNotEqualTo;
import org.opengis.filter.PropertyIsNull;
import org.opengis.filter.expression.Literal;
import org.opengis.filter.expression.PropertyName;
import org.opengis.filter.spatial.BBOX;
import org.opengis.filter.spatial.Beyond;
import org.opengis.filter.spatial.BinarySpatialOperator;
import org.opengis.filter.spatial.Contains;
import org.opengis.filter.spatial.Crosses;
import org.opengis.filter.spatial.DWithin;
import org.opengis.filter.spatial.Disjoint;
import org.opengis.filter.spatial.Equals;
import org.opengis.filter.spatial.Intersects;
import org.opengis.filter.spatial.Overlaps;
import org.opengis.filter.spatial.Touches;
import org.opengis.filter.spatial.Within;
import org.opengis.filter.temporal.After;
import org.opengis.filter.temporal.AnyInteracts;
import org.opengis.filter.temporal.Before;
import org.opengis.filter.temporal.Begins;
import org.opengis.filter.temporal.BegunBy;
import org.opengis.filter.temporal.BinaryTemporalOperator;
import org.opengis.filter.temporal.During;
import org.opengis.filter.temporal.EndedBy;
import org.opengis.filter.temporal.Ends;
import org.opengis.filter.temporal.Meets;
import org.opengis.filter.temporal.MetBy;
import org.opengis.filter.temporal.OverlappedBy;
import org.opengis.filter.temporal.TContains;
import org.opengis.filter.temporal.TEquals;
import org.opengis.filter.temporal.TOverlaps;

import com.vividsolutions.jts.geom.Envelope;
import com.vividsolutions.jts.geom.Geometry;


/** The purpose of this class is to split any Filter into two filters :
<ol><ul> a SpatialRestriction
*      <ul> and an OtherAttributesRestriction
<ol>
*  so we have :
*  OriginalFilter = SpatialRestriction && OtherAttributeRestriction
*
*  SpatialRestriction may actually be a rough approximation of OtherAttributeRestriction
*
* @author Christophe Rousson, SoC 2007, CRG-ULAVAL
*
*
*
*
*
* @source $URL$
*/
public class BBoxFilterSplitter implements FilterVisitor {
    private static FilterFactory filterFactory = CommonFactoryFinder.getFilterFactory2(null);
    private static final Envelope UNIVERSE_ENVELOPE = new Envelope(Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY, Double.NEGATIVE_INFINITY, Double.POSITIVE_INFINITY);
    private static final Envelope EMPTY_ENVELOPE = new Envelope();
   
    //envelopes that can be used to limit the
    //bounds of the data collected; if empty then equivalent to excludes filter
    private Stack<Envelope> envelopes = new Stack<Envelope>();
   
    private Stack<Filter> otherRestrictions = new Stack<Filter>();
    private String geom = null;
    private String srs = null;

    //private Stack notEnvelopes = new Stack() ;
    public Object visit(ExcludeFilter f, Object arg1) {
        envelopes.push(new Envelope(EMPTY_ENVELOPE));
        return null;
    }

    public Object visit(IncludeFilter f, Object arg1) {
        envelopes.push(new Envelope(UNIVERSE_ENVELOPE));
        return null;
    }
   
    public Object visit(Id f, Object arg1) {
        otherRestrictions.push(f);
        return null;
    }

    public Object visit(Not f, Object arg1) {
        //visit child
        f.getFilter().accept(this, arg1);
       
        //deal with envelope
        if (envelopes.size() > 0){
            //universe - envelope = universe
            envelopes.pop();
            envelopes.push(new Envelope(UNIVERSE_ENVELOPE));
        }
        otherRestrictions.push(f);
        return null;
    }
   
    public Object visit(And f, Object arg1) {
        int envSize = envelopes.size();
        int othSize = otherRestrictions.size();

        for (Iterator<Filter> it = f.getChildren().iterator(); it.hasNext();) {
            Filter child = (Filter) it.next();
            child.accept(this, arg1);
        }

        if (envelopes.size() >= (envSize + 2)) {
            Envelope e = (Envelope) envelopes.pop();
            for (int i = envelopes.size(); i > envSize; i--) {
                Envelope curr = (Envelope) envelopes.pop();
                if (curr.equals(EMPTY_ENVELOPE) || e.equals(EMPTY_ENVELOPE)){
                    e = new Envelope(EMPTY_ENVELOPE);
                }else if (curr.equals(UNIVERSE_ENVELOPE)){
                    //do nothing leave e alone
                    //universe & envelope = enevelope
                }else if (e.equals(UNIVERSE_ENVELOPE )){
                    e = curr;
                }else{
                    //must expand to include instead of intersects
                    //because two bounding boxes may be disjoint
                    //but a geometry may still intersect both of the
                    //bounding boxes
                    e.expandToInclude(curr);
                }
            }
            envelopes.push(e);
        }

        // in all case, we'll need original filter as computed SpatialRestriction is a rough approximation      
        multiplePop(otherRestrictions, othSize);
        Envelope top = envelopes.peek();
        if (!(top.equals(EMPTY_ENVELOPE))){
          otherRestrictions.push(f);
        }

        return null;
    }
   
    public Object visit(Or f, Object arg1) {
        int envSize = envelopes.size();
        int othSize = otherRestrictions.size();

        for (Iterator<Filter> it = f.getChildren().iterator(); it.hasNext();) {
            Filter child = (Filter) it.next();
            child.accept(this, arg1);
        }

        if (envelopes.size() > (envSize + 1)) {
            Envelope e = (Envelope) envelopes.pop();

            for (int i = envelopes.size(); i > envSize; i--) {
                e.expandToInclude((Envelope) envelopes.pop());
            }

            envelopes.push(e);
        } else if (envelopes.size() == (envSize + 1)) {
            // the trick is we cannot separate this filter in the form of SpatialRestriction && OtherRestriction
            // so we add this part to OtherRestriction
            envelopes.pop();
            envelopes.push(new Envelope(UNIVERSE_ENVELOPE));
        }

        // in all case, we'll need original filter as computed SpatialRestriction is a rough approximation
        int size = otherRestrictions.size();
        multiplePop(otherRestrictions, othSize);
        if (size > othSize){
            otherRestrictions.push(f);
        }

        return null;
    }

    public Object visit(PropertyIsBetween f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsEqualTo f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsNotEqualTo f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsGreaterThan f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsGreaterThanOrEqualTo f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsLessThan f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsLessThanOrEqualTo f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsLike f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsNull f, Object arg1) {
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(PropertyIsNil f, Object extraData) {
        otherRestrictions.push(f);
        return null;
    }

    public Object visit(BBOX f, Object arg1) {
        if (geom == null) {
            if (f.getExpression1() instanceof PropertyName){
                geom = ((PropertyName)f.getExpression1()).getPropertyName();
            }
            srs = f.getSRS();
                       
        }else{
            String newgeom = f.getExpression1() instanceof PropertyName ? ((PropertyName)f.getExpression1()).getPropertyName() : null;
            String newsrs = f.getSRS();
       
            if ((geom != newgeom) ||  srs != srs  ) {
                throw new UnsupportedOperationException(
                    "This splitter can not be used against a filter where different BBOX filters refer to different Geometry attributes.");
            }
        }
      
        Envelope e = new Envelope(f.getMinX(), f.getMaxX(), f.getMinY(), f.getMaxY());
        envelopes.push(e);
       
        return null;
    }

    public Object visit(Beyond f, Object arg1) {
        // we don't know how to handle this geometric restriction as a BBox
        // so we treat this as an attribute filter
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(Contains f, Object arg1) {
        // we don't know how to handle this geometric restriction as a BBox
        // so we treat this as an attribute filter
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(Crosses f, Object arg1) {
        // we don't know how to handle this geometric restriction as a BBox
        // so we treat this as an attribute filter
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(Disjoint f, Object arg1) {
        // we don't know how to handle this geometric restriction as a BBox
        // so we treat this as an attribute filter
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(DWithin f, Object arg1) {
        // we don't know how to handle this geometric restriction as a BBox
        // so we treat this as an attribute filter
        otherRestrictions.push(f);

        return null;
    }

    public Object visit(Equals f, Object arg1) {
        //       we don't know how to handle this geometric restriction as a BBox
        // so we treat this as an attribute filter
        otherRestrictions.push(f);

        return null;
    }

    protected void traverse(BinarySpatialOperator f) {
        if (f.getExpression1() instanceof Literal) {
            Literal l = (Literal) f.getExpression1();
            Geometry g = (Geometry) l.getValue();
            envelopes.push(g.getEnvelopeInternal());
        } else if (f.getExpression2() instanceof Literal) {
            Literal l = (Literal) f.getExpression2();
            Geometry g = (Geometry) l.getValue();
            envelopes.push(g.getEnvelopeInternal());
        }
       
        if (f.getExpression1() instanceof PropertyName){
            geom = ((PropertyName)f.getExpression1()).getPropertyName();
        }else if (f.getExpression2() instanceof PropertyName){
            geom = ((PropertyName)f.getExpression2()).getPropertyName();
        }
       
        otherRestrictions.push(f);
    }

    public Object visit(Intersects f, Object arg1) {
        traverse(f);

        return null;
    }

    public Object visit(Overlaps f, Object arg1) {
        traverse(f);

        return null;
    }

    public Object visit(Touches f, Object arg1) {
        traverse(f);

        return null;
    }

    public Object visit(Within f, Object arg1) {
        traverse(f);

        return null;
    }

    public Object visitNullFilter(Object arg0) {
        // TODO Auto-generated method stub
        return null;
    }
   
    //temporal
    public Object visit(After after, Object extraData) {
        return visit((BinaryTemporalOperator)after, extraData);
    }

    public Object visit(AnyInteracts anyInteracts, Object extraData) {
        return visit((BinaryTemporalOperator)anyInteracts, extraData);
    }

    public Object visit(Before before, Object extraData) {
        return visit((BinaryTemporalOperator)before, extraData);
    }

    public Object visit(Begins begins, Object extraData) {
        return visit((BinaryTemporalOperator)begins, extraData);
    }

    public Object visit(BegunBy begunBy, Object extraData) {
        return visit((BinaryTemporalOperator)begunBy, extraData);
    }

    public Object visit(During during, Object extraData) {
        return visit((BinaryTemporalOperator)during, extraData);
    }

    public Object visit(EndedBy endedBy, Object extraData) {
        return visit((BinaryTemporalOperator)endedBy, extraData);
    }

    public Object visit(Ends ends, Object extraData) {
        return visit((BinaryTemporalOperator)ends, extraData);
    }

    public Object visit(Meets meets, Object extraData) {
        return visit((BinaryTemporalOperator)meets, extraData);
    }

    public Object visit(MetBy metBy, Object extraData) {
        return visit((BinaryTemporalOperator)metBy, extraData);
    }

    public Object visit(OverlappedBy overlappedBy, Object extraData) {
        return visit((BinaryTemporalOperator)overlappedBy, extraData);
    }

    public Object visit(TContains contains, Object extraData) {
        return visit((BinaryTemporalOperator)contains, extraData);
    }

    public Object visit(TEquals equals, Object extraData) {
        return visit((BinaryTemporalOperator)equals, extraData);
    }

    public Object visit(TOverlaps contains, Object extraData) {
        return visit((BinaryTemporalOperator)contains, extraData);
    }
   
    protected Object visit(BinaryTemporalOperator filter, Object data) {
        otherRestrictions.add(filter);
        return null;
    }

    public Envelope getEnvelope() {
        assert (envelopes.size() < 2);

        if (envelopes.isEmpty()) {
            return null;
        } else {
            return (Envelope) envelopes.peek();
        }
    }

    /** Return the bbox part of original filter :
     *  filter == (1) AND (2), where
     *  (1) = BBOXImpl
     *  (2) = other filter
     *
     * @return filter part (1)
     */
    public Filter getFilterPre() {
        Envelope e = getEnvelope();

        if (e == null || e.isNull()) {
            return Filter.EXCLUDE;
            //return Filter.INCLUDE;
        } else if (e.equals(UNIVERSE_ENVELOPE)){
            return Filter.INCLUDE;
        } else {
            Filter myfilter = filterFactory.bbox(geom, e.getMinX(), e.getMinY(), e.getMaxX(), e.getMaxY(), srs);
            return myfilter;
        }
    }

    /** Return the non bbox part (2) of original filter :
     *  filter == (1) AND (2), where
     *  (1) = BBOXImpl
     *  (2) = other filter
     *
     * @return filter part (2)
     */
    public Filter getFilterPost() {
        if (otherRestrictions.isEmpty()) {
            return Filter.INCLUDE;
        } else if (otherRestrictions.size() == 1) {
            return (Filter) otherRestrictions.peek();
        } else {
            return filterFactory.and(otherRestrictions.subList(0,
                    otherRestrictions.size() - 1));
        }
    }

    private void multiplePop(Stack<Filter> s, int downsize) {
        for (int i = s.size(); i > downsize; i--) {
            s.pop();
        }
    }
}
TOP

Related Classes of org.geotools.caching.util.BBoxFilterSplitter

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.