001: /*
002: * Licensed to the Apache Software Foundation (ASF) under one or more
003: * contributor license agreements. See the NOTICE file distributed with
004: * this work for additional information regarding copyright ownership.
005: * The ASF licenses this file to You under the Apache License, Version 2.0
006: * (the "License"); you may not use this file except in compliance with
007: * the License. You may obtain a copy of the License at
008: *
009: * http://www.apache.org/licenses/LICENSE-2.0
010: *
011: * Unless required by applicable law or agreed to in writing, software
012: * distributed under the License is distributed on an "AS IS" BASIS,
013: * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
014: * See the License for the specific language governing permissions and
015: * limitations under the License.
016: */
017:
018: /* $Id: NumericOp.java 426576 2006-07-28 15:44:37Z jeremias $ */
019:
020: package org.apache.fop.fo.expr;
021:
022: import org.apache.fop.datatypes.PercentBaseContext;
023: import org.apache.fop.datatypes.Numeric;
024:
025: /**
026: * This class contains static methods to evaluate operations on Numeric
027: * operands. If the operands are absolute numerics the result is computed
028: * rigth away and a new absolute numeric is return. If one of the operands are
029: * relative a n operation node is created with the operation and the operands.
030: * The evaluation of the operation can then occur when getNumericValue() is
031: * called.
032: */
033: public class NumericOp {
034: /**
035: * Add the two operands and return a new Numeric representing the result.
036: * @param op1 The first operand.
037: * @param op2 The second operand.
038: * @return A Numeric representing the result.
039: * @throws PropertyException If the dimension of the operand is different
040: * from the dimension of this Numeric.
041: */
042: public static Numeric addition(Numeric op1, Numeric op2)
043: throws PropertyException {
044: if (op1.isAbsolute() && op2.isAbsolute()) {
045: return addition2(op1, op2, null);
046: } else {
047: return new RelativeNumericProperty(
048: RelativeNumericProperty.ADDITION, op1, op2);
049: }
050: }
051:
052: public static Numeric addition2(Numeric op1, Numeric op2,
053: PercentBaseContext context) throws PropertyException {
054: if (op1.getDimension() != op2.getDimension()) {
055: throw new PropertyException(
056: "Can't subtract Numerics of different dimensions");
057: }
058: return numeric(op1.getNumericValue(context)
059: + op2.getNumericValue(context), op1.getDimension());
060: }
061:
062: /**
063: * Add the second operand from the first and return a new Numeric
064: * representing the result.
065: * @param op1 The first operand.
066: * @param op2 The second operand.
067: * @return A Numeric representing the result.
068: * @throws PropertyException If the dimension of the operand is different
069: * from the dimension of this Numeric.
070: */
071: public static Numeric subtraction(Numeric op1, Numeric op2)
072: throws PropertyException {
073: if (op1.isAbsolute() && op2.isAbsolute()) {
074: return subtraction2(op1, op2, null);
075: } else {
076: return new RelativeNumericProperty(
077: RelativeNumericProperty.SUBTRACTION, op1, op2);
078: }
079: }
080:
081: public static Numeric subtraction2(Numeric op1, Numeric op2,
082: PercentBaseContext context) throws PropertyException {
083: if (op1.getDimension() != op2.getDimension()) {
084: throw new PropertyException(
085: "Can't subtract Numerics of different dimensions");
086: }
087: return numeric(op1.getNumericValue(context)
088: - op2.getNumericValue(context), op1.getDimension());
089: }
090:
091: /**
092: * Multiply the two operands and return a new Numeric representing the
093: * result.
094: * @param op1 The first operand.
095: * @param op2 The second operand.
096: * @return A Numeric representing the result.
097: * @throws PropertyException If the dimension of the operand is different
098: * from the dimension of this Numeric.
099: */
100: public static Numeric multiply(Numeric op1, Numeric op2)
101: throws PropertyException {
102: if (op1.isAbsolute() && op2.isAbsolute()) {
103: return multiply2(op1, op2, null);
104: } else {
105: return new RelativeNumericProperty(
106: RelativeNumericProperty.MULTIPLY, op1, op2);
107: }
108: }
109:
110: public static Numeric multiply2(Numeric op1, Numeric op2,
111: PercentBaseContext context) throws PropertyException {
112: return numeric(op1.getNumericValue(context)
113: * op2.getNumericValue(context), op1.getDimension()
114: + op2.getDimension());
115: }
116:
117: /**
118: * Divide the second operand into the first and return a new
119: * Numeric representing the
120: * result.
121: * @param op1 The first operand.
122: * @param op2 The second operand.
123: * @return A Numeric representing the result.
124: * @throws PropertyException If the dimension of the operand is different
125: * from the dimension of this Numeric.
126: */
127: public static Numeric divide(Numeric op1, Numeric op2)
128: throws PropertyException {
129: if (op1.isAbsolute() && op2.isAbsolute()) {
130: return divide2(op1, op2, null);
131: } else {
132: return new RelativeNumericProperty(
133: RelativeNumericProperty.DIVIDE, op1, op2);
134: }
135: }
136:
137: public static Numeric divide2(Numeric op1, Numeric op2,
138: PercentBaseContext context) throws PropertyException {
139: return numeric(op1.getNumericValue(context)
140: / op2.getNumericValue(context), op1.getDimension()
141: - op2.getDimension());
142: }
143:
144: /**
145: * Return the remainder of a division of the two operand Numeric.
146: * @param op1 The first operand.
147: * @param op2 The second operand.
148: * @return A new Numeric object representing the absolute value.
149: */
150: public static Numeric modulo(Numeric op1, Numeric op2)
151: throws PropertyException {
152: if (op1.isAbsolute() && op2.isAbsolute()) {
153: return modulo2(op1, op2, null);
154: } else {
155: return new RelativeNumericProperty(
156: RelativeNumericProperty.MODULO, op1, op2);
157: }
158: }
159:
160: public static Numeric modulo2(Numeric op1, Numeric op2,
161: PercentBaseContext context) throws PropertyException {
162: return numeric(op1.getNumericValue(context)
163: % op2.getNumericValue(context), op1.getDimension());
164: }
165:
166: /**
167: * Return the absolute value of a Numeric.
168: * @param op the operand.
169: * @return a new Numeric object representing the absolute value of the operand.
170: */
171: public static Numeric abs(Numeric op) throws PropertyException {
172: if (op.isAbsolute()) {
173: return abs2(op, null);
174: } else {
175: return new RelativeNumericProperty(
176: RelativeNumericProperty.ABS, op);
177: }
178: }
179:
180: public static Numeric abs2(Numeric op, PercentBaseContext context)
181: throws PropertyException {
182: return numeric(Math.abs(op.getNumericValue(context)), op
183: .getDimension());
184: }
185:
186: /**
187: * Return the negation of a Numeric.
188: * @param op the operand.
189: * @return a new Numeric object representing the negation of the operand.
190: */
191: public static Numeric negate(Numeric op) throws PropertyException {
192: if (op.isAbsolute()) {
193: return negate2(op, null);
194: } else {
195: return new RelativeNumericProperty(
196: RelativeNumericProperty.NEGATE, op);
197: }
198: }
199:
200: public static Numeric negate2(Numeric op, PercentBaseContext context)
201: throws PropertyException {
202: return numeric(-op.getNumericValue(context), op.getDimension());
203: }
204:
205: /**
206: * Return the larger of the two Numerics.
207: * @param op1 The first operand.
208: * @param op2 The second operand.
209: * @return a Numeric which is the maximum of the two operands.
210: * @throws PropertyException if the dimensions or value types of the operands are different.
211: */
212: public static Numeric max(Numeric op1, Numeric op2)
213: throws PropertyException {
214: if (op1.isAbsolute() && op2.isAbsolute()) {
215: return max2(op1, op2, null);
216: } else {
217: return new RelativeNumericProperty(
218: RelativeNumericProperty.MAX, op1, op2);
219: }
220: }
221:
222: public static Numeric max2(Numeric op1, Numeric op2,
223: PercentBaseContext context) throws PropertyException {
224: if (op1.getDimension() != op2.getDimension()) {
225: throw new PropertyException(
226: "Arguments to max() must have same dimensions");
227: }
228: return op1.getNumericValue(context) > op2
229: .getNumericValue(context) ? op1 : op2;
230: }
231:
232: /**
233: * Return the smaller of two Numerics.
234: * @param op1 The first operand.
235: * @param op2 The second operand.
236: * @return a Numeric which is the minimum of the two operands.
237: * @throws PropertyException if the dimensions or value types of the operands are different.
238: */
239: public static Numeric min(Numeric op1, Numeric op2)
240: throws PropertyException {
241: if (op1.isAbsolute() && op2.isAbsolute()) {
242: return min2(op1, op2, null);
243: } else {
244: return new RelativeNumericProperty(
245: RelativeNumericProperty.MIN, op1, op2);
246: }
247: }
248:
249: public static Numeric min2(Numeric op1, Numeric op2,
250: PercentBaseContext context) throws PropertyException {
251: if (op1.getDimension() != op2.getDimension()) {
252: throw new PropertyException(
253: "Arguments to min() must have same dimensions");
254: }
255: return op1.getNumericValue(context) <= op2
256: .getNumericValue(context) ? op1 : op2;
257: }
258:
259: /**
260: * Create a new absolute numeric with the specified value and dimension.
261: * @param value
262: * @param dimension
263: * @return a new absolute numeric.
264: */
265: private static Numeric numeric(double value, int dimension) {
266: return new NumericProperty(value, dimension);
267: }
268: }
|