All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.geotools.feature.visitor.AverageVisitor Maven / Gradle / Ivy

Go to download

The main module contains the GeoTools public interfaces that are used by other GeoTools modules (and GeoTools applications). Where possible we make use industry standard terms as provided by OGC and ISO standards. The formal GeoTools public api consists of gt-metadata, jts and the gt-main module. The main module contains the default implementations that are available provided to other GeoTools modules using our factory system. Factories are obtained from an appropriate FactoryFinder, giving applications a chance configure the factory used using the Factory Hints facilities. FilterFactory ff = CommonFactoryFinder.getFilterFactory(); Expression expr = ff.add( expression1, expression2 ); If you find yourself using implementation specific classes chances are you doing it wrong: Expression expr = new AddImpl( expression1, expressiom2 );

The newest version!
/*
 *    GeoTools - The Open Source Java GIS Toolkit
 *    http://geotools.org
 *
 *    (C) 2005-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.feature.visitor;

import java.util.Arrays;
import java.util.Collections;
import java.util.List;
import java.util.Optional;
import org.geotools.data.simple.SimpleFeatureCollection;
import org.geotools.factory.CommonFactoryFinder;
import org.geotools.filter.IllegalFilterException;
import org.opengis.feature.Feature;
import org.opengis.feature.simple.SimpleFeature;
import org.opengis.feature.simple.SimpleFeatureType;
import org.opengis.feature.type.AttributeDescriptor;
import org.opengis.filter.FilterFactory;
import org.opengis.filter.expression.Expression;

/**
 * Calculates the Average
 *
 * @author Cory Horner, Refractions
 * @since 2.2.M2
 */
public class AverageVisitor implements FeatureCalc, FeatureAttributeVisitor {
    private Expression expr;

    /**
     * This flag lets us know that an optimized result was stored and therefore we don't have enough
     * data to perform any merges.
     */
    private boolean isOptimized = false;

    AverageStrategy strategy;

    /**
     * Constructor class for the AverageVisitor using AttributeDescriptor ID
     *
     * @param attributeTypeIndex integer representing the AttributeDescriptor
     * @param type FeatureType
     */
    public AverageVisitor(int attributeTypeIndex, SimpleFeatureType type)
            throws IllegalFilterException {
        FilterFactory factory = CommonFactoryFinder.getFilterFactory(null);
        AttributeDescriptor attributeType = type.getDescriptor(attributeTypeIndex);
        expr = factory.property(attributeType.getLocalName());
        createStrategy(attributeType.getType().getBinding());
    }

    /**
     * Constructor class for the AverageVisitor using AttributeDescriptor Name
     *
     * @param attrName string respresenting the AttributeDescriptor
     * @param type FeatureType
     */
    public AverageVisitor(String attrName, SimpleFeatureType type) throws IllegalFilterException {
        FilterFactory factory = CommonFactoryFinder.getFilterFactory(null);
        AttributeDescriptor attributeType = type.getDescriptor(attrName);
        expr = factory.property(attributeType.getLocalName());
        createStrategy(attributeType.getType().getBinding());
    }

    /** Constructor class for the AverageVisitor using an expression */
    public AverageVisitor(Expression expr) throws IllegalFilterException {
        this.expr = expr;
    }

    public void init(SimpleFeatureCollection collection) {
        // do nothing
    }

    @Override
    public List getExpressions() {
        return Arrays.asList(expr);
    }

    @Override
    public Optional> getResultType(List inputTypes) {
        if (inputTypes == null || inputTypes.size() != 1)
            throw new IllegalArgumentException(
                    "Expecting a single type in input, not " + inputTypes);

        Class type = inputTypes.get(0);
        if (Number.class.isAssignableFrom(type)) {
            return Optional.of(Collections.singletonList(Double.class));
        }
        throw new IllegalArgumentException(
                "The input type for sum must be numeric, instead this was found: " + type);
    }

    /**
     * Factory method for creating the appropriate strategy object
     *
     * 

* * @param type the class to use for the calculation * @return a strategy object of the correct data type to be used for calculating the average */ private static AverageStrategy createStrategy(Class type) { if (type == Integer.class) { return new IntegerAverageStrategy(); } else if (type == Long.class) { return new LongAverageStrategy(); } else if (type == Float.class) { return new FloatAverageStrategy(); } else if (Number.class.isAssignableFrom(type)) return new DoubleAverageStrategy(); return null; } public void visit(SimpleFeature feature) { visit((Feature) feature); } public void visit(org.opengis.feature.Feature feature) { Object value = expr.evaluate(feature); if (value != null) { if (strategy == null) { Class type = value.getClass(); strategy = createStrategy(type); } strategy.add(value); } } public Expression getExpression() { return expr; } /** * Returns the average from the visitor's current * * @return the average */ public Object getAverage() { return strategy.getResult(); } /** Resets the "Average" strategy pattern */ public void reset() { strategy = null; isOptimized = false; } /** Returns a CalcResult object (containing the Average) */ public CalcResult getResult() { if (strategy == null) { return CalcResult.NULL_RESULT; } return new AverageResult(strategy, isOptimized); } public void setValue(Object newAverage) { reset(); Class type = newAverage.getClass(); strategy = createStrategy(type); strategy.add(newAverage); isOptimized = true; } public void setValue(int newCount, Object newSum) { reset(); strategy = createStrategy(newSum.getClass()); strategy.set(newCount, newSum); isOptimized = false; // this is an optimization, but we have the same // information we would otherwise have if we had // in fact visited each feature } /** Encapsulates the strategy pattern for the "Average" Visitor */ interface AverageStrategy { public void add(Object value); public Object getResult(); public Object getSum(); public int getCount(); public void set(int count, Object sum); } /** Implements the average calculation for values of the type double */ static class DoubleAverageStrategy implements AverageStrategy { double number = 0; int count = 0; public void add(Object value) { number += ((Number) value).doubleValue(); count++; } public Object getResult() { return Double.valueOf(number / count); } public Object getSum() { return Double.valueOf(number); } public int getCount() { return count; } public void set(int newCount, Object sum) { number = ((Number) sum).doubleValue(); count = newCount; } } /** Implements the average calculation for values of the type float */ static class FloatAverageStrategy implements AverageStrategy { float number = 0; int count = 0; public void add(Object value) { number += ((Number) value).floatValue(); count++; } public Object getResult() { return Float.valueOf((float) number / count); } public Object getSum() { return Float.valueOf(number); } public int getCount() { return count; } public void set(int newCount, Object sum) { number = ((Number) sum).floatValue(); count = newCount; } } /** Implements the average calculation for values of the type long */ static class LongAverageStrategy implements AverageStrategy { long number = 0; int count = 0; public void add(Object value) { number += ((Number) value).longValue(); count++; } public Object getResult() { return Double.valueOf((double) number / count); } public Object getSum() { return Long.valueOf(number); } public int getCount() { return count; } public void set(int newCount, Object sum) { number = ((Number) sum).longValue(); count = newCount; } } /** Implements the average calculation for values of the type integer */ static class IntegerAverageStrategy implements AverageStrategy { int number = 0; int count = 0; public void add(Object value) { number += ((Number) value).intValue(); count++; } public Object getResult() { return Double.valueOf((double) number / count); } public Object getSum() { return Integer.valueOf(number); } public int getCount() { return count; } public void set(int newCount, Object sum) { number = ((Number) sum).intValue(); count = newCount; } } /** */ public static class AverageResult extends AbstractCalcResult { private AverageStrategy averageStrategy; private boolean isOptimized = false; public AverageResult(Object newAverageStrategy) { averageStrategy = (AverageStrategy) newAverageStrategy; } public AverageResult(Object newAverageStrategy, boolean isOptimized) { averageStrategy = (AverageStrategy) newAverageStrategy; this.isOptimized = isOptimized; } public AverageResult(int newCount, Object newSum) { averageStrategy = createStrategy(newSum.getClass()); averageStrategy.set(newCount, newSum); } public Object getResult() { return averageStrategy.getResult(); } public Object getValue() { return averageStrategy.getResult(); } /** * The count used to calculate the average * * @return the count, or -1 if unknown */ public int getCount() { if (isOptimized) { return -1; // there is no count, as an optimization was used. } else { return averageStrategy.getCount(); } } /** The sum used to calculate the average */ public Object getSum() { if (isOptimized) { return null; } else { return averageStrategy.getSum(); } } /** * Determines if the target CalcResult object can be merged with this CalcResult object * * @param targetResults a second CalcResult object (target) * @return boolean */ public boolean isCompatible(CalcResult targetResults) { if (targetResults instanceof AverageResult || targetResults == CalcResult.NULL_RESULT) { return true; } else { return false; } } /** * Merges the contents of a CalcResult Object with another CalcResult Object. If the two * CalcResult objects are compatible, the merged result (a new object) is returned. * * @param resultsToAdd the CalcResult to merge the results with * @return a new merged CalcResult object * @throws IllegalArgumentException when the resultsToAdd are inappropriate */ public CalcResult merge(CalcResult resultsToAdd) { if (!isCompatible(resultsToAdd)) { throw new IllegalArgumentException("Parameter is not a compatible type"); } if (resultsToAdd == CalcResult.NULL_RESULT) { return this; } if (resultsToAdd instanceof AverageResult) { AverageResult moreResults = (AverageResult) resultsToAdd; // ensure both results are NOT optimized if (isOptimized || moreResults.isOptimized) { throw new IllegalArgumentException( "Optimized average results cannot be merged."); } Number[] sums = new Number[] { (Number) averageStrategy.getSum(), (Number) moreResults.averageStrategy.getSum() }; Number newSum = CalcUtil.sum(sums); Number newCount = (Number) Integer.valueOf( averageStrategy.getCount() + moreResults.averageStrategy.getCount()); Number[] params = new Number[] {newSum, newCount}; Object newAverage = CalcUtil.getObject(params); AverageStrategy newAverageObj; newAverageObj = createStrategy(newAverage.getClass()); newAverageObj.set(newCount.intValue(), newSum); return new AverageResult(newAverageObj); } else { throw new IllegalArgumentException( "The CalcResults claim to be compatible, but the appropriate merge method has not been implemented."); } } } }





© 2015 - 2024 Weber Informatics LLC | Privacy Policy