/* * Licensed to the Apache Software Foundation (ASF) under one or more * contributor license agreements. See the NOTICE file distributed with * this work for additional information regarding copyright ownership. * The ASF licenses this file to You under the Apache License, Version 2.0 * (the "License"); you may not use this file except in compliance with * the License. You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ /* $Id$ */ package org.apache.fop.fo.expr; import org.apache.fop.datatypes.Numeric; import org.apache.fop.datatypes.PercentBaseContext; /** * This class contains static methods to evaluate operations on Numeric * operands. If the operands are absolute numerics the result is computed * rigth away and a new absolute numeric is return. If one of the operands are * relative a n operation node is created with the operation and the operands. * The evaluation of the operation can then occur when getNumericValue() is * called. */ public final class NumericOp { private NumericOp() { } /** * Add the two operands and return a new Numeric representing the result. * @param op1 The first operand. * @param op2 The second operand. * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric addition(Numeric op1, Numeric op2) throws PropertyException { if (op1.isAbsolute() && op2.isAbsolute()) { return addition2(op1, op2, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.ADDITION, op1, op2); } } /** * Add the two operands with a percentage context * and return a new Numeric representing the result. * @param op1 The first operand. * @param op2 The second operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric addition2(Numeric op1, Numeric op2, PercentBaseContext context) throws PropertyException { if (op1.getDimension() != op2.getDimension()) { throw new PropertyException("Can't subtract Numerics of different dimensions"); } return numeric(op1.getNumericValue(context) + op2.getNumericValue(context), op1.getDimension()); } /** * Add the second operand from the first and return a new Numeric * representing the result. * @param op1 The first operand. * @param op2 The second operand. * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric subtraction(Numeric op1, Numeric op2) throws PropertyException { if (op1.isAbsolute() && op2.isAbsolute()) { return subtraction2(op1, op2, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.SUBTRACTION, op1, op2); } } /** * Subtract the two operands with a percentage context * and return a new Numeric representing the result. * @param op1 The first operand. * @param op2 The second operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric subtraction2(Numeric op1, Numeric op2, PercentBaseContext context) throws PropertyException { if (op1.getDimension() != op2.getDimension()) { throw new PropertyException("Can't subtract Numerics of different dimensions"); } return numeric(op1.getNumericValue(context) - op2.getNumericValue(context), op1.getDimension()); } /** * Multiply the two operands and return a new Numeric representing the * result. * @param op1 The first operand. * @param op2 The second operand. * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric multiply(Numeric op1, Numeric op2) throws PropertyException { if (op1.isAbsolute() && op2.isAbsolute()) { return multiply2(op1, op2, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.MULTIPLY, op1, op2); } } /** * Multiply the two operands with a percentage context * and return a new Numeric representing the result. * @param op1 The first operand. * @param op2 The second operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric multiply2(Numeric op1, Numeric op2, PercentBaseContext context) throws PropertyException { return numeric(op1.getNumericValue(context) * op2.getNumericValue(context), op1.getDimension() + op2.getDimension()); } /** * Divide the second operand into the first and return a new * Numeric representing the * result. * @param op1 The first operand. * @param op2 The second operand. * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric divide(Numeric op1, Numeric op2) throws PropertyException { if (op1.isAbsolute() && op2.isAbsolute()) { return divide2(op1, op2, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.DIVIDE, op1, op2); } } /** * Divide the two operands with a percentage context * and return a new Numeric representing the result. * @param op1 The first operand. * @param op2 The second operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric divide2(Numeric op1, Numeric op2, PercentBaseContext context) throws PropertyException { return numeric(op1.getNumericValue(context) / op2.getNumericValue(context), op1.getDimension() - op2.getDimension()); } /** * Return the remainder of a division of the two operand Numeric. * @param op1 The first operand. * @param op2 The second operand. * @return A new Numeric object representing the absolute value. * @throws PropertyException if a property exception occurs */ public static Numeric modulo(Numeric op1, Numeric op2) throws PropertyException { if (op1.isAbsolute() && op2.isAbsolute()) { return modulo2(op1, op2, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.MODULO, op1, op2); } } /** * Return the remainder of a division of the two operand Numeric. * @param op1 The first operand. * @param op2 The second operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric modulo2(Numeric op1, Numeric op2, PercentBaseContext context) throws PropertyException { return numeric(op1.getNumericValue(context) % op2.getNumericValue(context), op1.getDimension()); } /** * Return the absolute value of a Numeric. * @param op the operand. * @return a new Numeric object representing the absolute value of the operand. * @throws PropertyException if a property exception occurs */ public static Numeric abs(Numeric op) throws PropertyException { if (op.isAbsolute()) { return abs2(op, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.ABS, op); } } /** * Return the absolute value of a Numeric. * @param op the operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric abs2(Numeric op, PercentBaseContext context) throws PropertyException { return numeric(Math.abs(op.getNumericValue(context)), op.getDimension()); } /** * Return the negation of a Numeric. * @param op the operand. * @return a new Numeric object representing the negation of the operand. * @throws PropertyException if a property exception occurs */ public static Numeric negate(Numeric op) throws PropertyException { if (op.isAbsolute()) { return negate2(op, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.NEGATE, op); } } /** * Return the negation of a Numeric. * @param op the operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric negate2(Numeric op, PercentBaseContext context) throws PropertyException { return numeric(-op.getNumericValue(context), op.getDimension()); } /** * Return the larger of the two Numerics. * @param op1 The first operand. * @param op2 The second operand. * @return a Numeric which is the maximum of the two operands. * @throws PropertyException if the dimensions or value types of the operands are different. */ public static Numeric max(Numeric op1, Numeric op2) throws PropertyException { if (op1.isAbsolute() && op2.isAbsolute()) { return max2(op1, op2, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.MAX, op1, op2); } } /** * Return the larger of the two Numerics. * @param op1 The first operand. * @param op2 The second operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric max2(Numeric op1, Numeric op2, PercentBaseContext context) throws PropertyException { if (op1.getDimension() != op2.getDimension()) { throw new PropertyException("Arguments to max() must have same dimensions"); } return op1.getNumericValue(context) > op2.getNumericValue(context) ? op1 : op2; } /** * Return the smaller of two Numerics. * @param op1 The first operand. * @param op2 The second operand. * @return a Numeric which is the minimum of the two operands. * @throws PropertyException if the dimensions or value types of the operands are different. */ public static Numeric min(Numeric op1, Numeric op2) throws PropertyException { if (op1.isAbsolute() && op2.isAbsolute()) { return min2(op1, op2, null); } else { return new RelativeNumericProperty(RelativeNumericProperty.MIN, op1, op2); } } /** * Return the smaller of the two Numerics. * @param op1 The first operand. * @param op2 The second operand. * @param context a percent base context * @return A Numeric representing the result. * @throws PropertyException If the dimension of the operand is different * from the dimension of this Numeric. */ public static Numeric min2(Numeric op1, Numeric op2, PercentBaseContext context) throws PropertyException { if (op1.getDimension() != op2.getDimension()) { throw new PropertyException("Arguments to min() must have same dimensions"); } return op1.getNumericValue(context) <= op2.getNumericValue(context) ? op1 : op2; } /** * Create a new absolute numeric with the specified value and dimension. * @param value of numeric * @param dimension of numeric * @return a new absolute numeric. */ private static Numeric numeric(double value, int dimension) { return new NumericProperty(value, dimension); } }