/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2012, 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.filter.function.math; import java.util.Collections; import java.util.List; import org.geotools.filter.capability.FunctionNameImpl; import org.geotools.util.Converters; import org.opengis.filter.capability.FunctionName; import org.opengis.filter.expression.Expression; import org.opengis.filter.expression.ExpressionVisitor; import org.opengis.filter.expression.Function; import org.opengis.filter.expression.Literal; /** * Implements the Knuth floored division modulo_operation * * @see <a href="http://en.wikipedia.org/wiki/Modulo_operation#Remainder_calculation_for_the_modulo_operation">Modulo_operation</a> */ public class ModuloFunction implements Function { static FunctionName NAME = new FunctionNameImpl( "modulo", Integer.class, FunctionNameImpl.parameter("dividend", Integer.class), FunctionNameImpl.parameter("divisor", Integer.class) ); private final FunctionName functionName; private final List<Expression> parameters; private final Literal fallback; public ModuloFunction() { this.functionName = NAME; this.parameters = Collections.emptyList(); this.fallback = null; } public ModuloFunction(List<Expression> parameters, Literal fallback) { if (parameters == null) { throw new NullPointerException("parameters must be provided"); } if (parameters.size() != NAME.getArguments().size()) { throw new IllegalArgumentException(NAME.getArguments().size() + " function parameters are required"); } this.functionName = NAME; this.parameters = parameters; this.fallback = fallback; } public Object evaluate(Object object) { return evaluate(object, functionName.getReturn().getType()); } public <T> T evaluate(Object object, Class<T> context) { Expression dividendExpression = parameters.get(0); int dividend = dividendExpression.evaluate(object, Integer.class); Expression divisorExpression = parameters.get(1); int divisor = divisorExpression.evaluate(object, Integer.class); if (divisor == 0) { throw new IllegalArgumentException("divisor cannot be 0"); } int modulo = dividend - divisor * (int) Math.floor((double) dividend / divisor); return Converters.convert(modulo, context); } public Object accept(ExpressionVisitor visitor, Object extraData) { return visitor.visit(this, extraData); } public String getName() { return functionName.getName(); } public FunctionName getFunctionName() { return functionName; } public List<Expression> getParameters() { return Collections.unmodifiableList(parameters); } public Literal getFallbackValue() { return fallback; } }