KickJava   Java API By Example, From Geeks To Geeks.

Java > Open Source Codes > org > apache > fop > fo > expr > Numeric


1 /*
2  * $Id: Numeric.java,v 1.4.2.3 2003/02/25 12:56:58 jeremias Exp $
3  * ============================================================================
4  * The Apache Software License, Version 1.1
5  * ============================================================================
6  *
7  * Copyright (C) 1999-2003 The Apache Software Foundation. All rights reserved.
8  *
9  * Redistribution and use in source and binary forms, with or without modifica-
10  * tion, are permitted provided that the following conditions are met:
11  *
12  * 1. Redistributions of source code must retain the above copyright notice,
13  * this list of conditions and the following disclaimer.
14  *
15  * 2. Redistributions in binary form must reproduce the above copyright notice,
16  * this list of conditions and the following disclaimer in the documentation
17  * and/or other materials provided with the distribution.
18  *
19  * 3. The end-user documentation included with the redistribution, if any, must
20  * include the following acknowledgment: "This product includes software
21  * developed by the Apache Software Foundation (http://www.apache.org/)."
22  * Alternately, this acknowledgment may appear in the software itself, if
23  * and wherever such third-party acknowledgments normally appear.
24  *
25  * 4. The names "FOP" and "Apache Software Foundation" must not be used to
26  * endorse or promote products derived from this software without prior
27  * written permission. For written permission, please contact
28  * apache@apache.org.
29  *
30  * 5. Products derived from this software may not be called "Apache", nor may
31  * "Apache" appear in their name, without prior written permission of the
32  * Apache Software Foundation.
33  *
34  * THIS SOFTWARE IS PROVIDED ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES,
35  * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND
36  * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
37  * APACHE SOFTWARE FOUNDATION OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
38  * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLU-
39  * DING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS
40  * OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON
41  * ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
42  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
43  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
44  * ============================================================================
45  *
46  * This software consists of voluntary contributions made by many individuals
47  * on behalf of the Apache Software Foundation and was originally created by
48  * James Tauber <jtauber@jtauber.com>. For more information on the Apache
49  * Software Foundation, please see <http://www.apache.org/>.
50  */

51 package org.apache.fop.fo.expr;
52
53 import org.apache.fop.datatypes.Length;
54 import org.apache.fop.datatypes.FixedLength;
55 import org.apache.fop.datatypes.PercentLength;
56 import org.apache.fop.datatypes.MixedLength;
57 import org.apache.fop.datatypes.TableColLength;
58 import org.apache.fop.datatypes.PercentBase;
59
60 import java.util.ArrayList JavaDoc;
61
62 /**
63  * Represents a "numeric" value as defined by the XSL FO Specification.
64  * This consists of one or more kinds of value specifications, from
65  * absolute numbers (units power of 0) to lengths (unit power of 1),
66  * relative lengths (ems), percentage lengths.
67  * A Numeric can be constructed from other Property types representing
68  * Numbers or Length-type values.
69  * Numeric provides methods to return Number and Length values based on
70  * its current value.
71  * It supports basic arithmetic operations involving Numerics.
72  */

73 public class Numeric {
74     // Bit fields
75
public static final int ABS_LENGTH = 1; // abs units (or number)
76
public static final int PC_LENGTH = 2; // Percentage
77
public static final int TCOL_LENGTH = 4; // Table units
78

79     private int valType;
80     private double absValue;
81     private double pcValue;
82     private PercentBase pcBase = null; // base value for PC_LENGTH component
83
private double tcolValue;
84     private int dim;
85
86
87     /**
88      * Construct a Numeric object by specifying one or more components,
89      * including absolute length, percent length, table units.
90      * @param valType A combination of bits representing the value types.
91      * @param absValue The value of a Number or resolved Length value if
92      * the ABS_LENGTH flag is set.
93      * @param pcValue The decimal percent value if the PC_LENGTH flag is set
94      * @param tcolValue The decimal table unit value if the TCOL_LENGTH flag
95      * is set.
96      * @param dim The dimension of the value. 0 for a Number, 1 for a Length
97      * (any type), >1, <0 if Lengths have been multiplied or divided.
98      * @pcBase The PercentBase object used to calculate an actual value for
99      * a PC_LENGTH.
100      */

101     protected Numeric(int valType, double absValue, double pcValue,
102                       double tcolValue, int dim, PercentBase pcBase) {
103         this.valType = valType;
104         this.absValue = absValue;
105         this.pcValue = pcValue;
106         this.tcolValue = tcolValue;
107         this.dim = dim;
108         this.pcBase = pcBase;
109     }
110
111     /**
112      * Construct a Numeric object of dimension 0 from a double.
113      * @param valType A combination of bits representing the value types.
114      * @param absValue The value of a Number or resolved Length value.
115      */

116
117     /**
118      * *
119      * protected Numeric(int valType, double absValue) {
120      * this.valType = valType;
121      * this.absValue = absValue;
122      * }
123      */

124
125     /**
126      * Construct a Numeric object from a Number.
127      * @param num The number.
128      */

129     public Numeric(Number JavaDoc num) {
130         this(ABS_LENGTH, num.doubleValue(), 0.0, 0.0, 0, null);
131     }
132
133     /**
134      * Construct a Numeric object from a Length.
135      * @param l The Length.
136      */

137     public Numeric(FixedLength l) {
138         this(ABS_LENGTH, (double)l.mvalue(), 0.0, 0.0, 1, null);
139     }
140
141     /**
142      * Construct a Numeric object from a PercentLength.
143      * @param pclen The PercentLength.
144      */

145     public Numeric(PercentLength pclen) {
146         this(PC_LENGTH, 0.0, pclen.value(), 0.0, 1, pclen.getBaseLength());
147     }
148
149     /**
150      * Construct a Numeric object from a TableColLength.
151      * @param tclen The TableColLength.
152      */

153     public Numeric(TableColLength tclen) {
154         this(TCOL_LENGTH, 0.0, 0.0, tclen.getTableUnits(), 1, null);
155     }
156
157
158     /**
159      * Return the current value as a Length if possible. This constructs
160      * a new Length or Length subclass based on the current value type
161      * of the Numeric.
162      * If the stored value has a unit dimension other than 1, null
163      * is returned.
164      */

165     public Length asLength() {
166         if (dim == 1) {
167             ArrayList JavaDoc len = new ArrayList JavaDoc(3);
168             if ((valType & ABS_LENGTH) != 0) {
169                 len.add(new FixedLength((int)absValue));
170             }
171             if ((valType & PC_LENGTH) != 0) {
172                 len.add(new PercentLength(pcValue, pcBase));
173             }
174             if ((valType & TCOL_LENGTH) != 0) {
175                 len.add(new TableColLength(tcolValue));
176             }
177             if (len.size() == 1) {
178                 return (Length)len.get(0);
179             } else {
180                 return new MixedLength(len);
181             }
182         } else {
183             // or throw exception???
184
// can't make Length if dimension != 1
185
return null;
186         }
187     }
188
189     /**
190      * Return the current value as a Number if possible.
191      * Calls asDouble().
192      */

193     public Number JavaDoc asNumber() {
194         return asDouble();
195     }
196
197     public Double JavaDoc asDouble() {
198         if (dim == 0 && valType == ABS_LENGTH) {
199             return new Double JavaDoc(absValue);
200         } else {
201             // or throw exception???
202
// can't make Number if dimension != 0
203
return null;
204         }
205     }
206
207     /**
208      * Return the current value as a Integer if possible.
209      * If the unit dimension is 0 and the value type is ABSOLUTE, an Integer
210      * is returned. Otherwise null is returned. Note: the current value is
211      * truncated if necessary to make an integer value.
212      */

213
214     /**
215      * public Integer asInteger() {
216      * if (dim == 0 && valType==ABS_LENGTH) {
217      * return new Integer((int)absValue);
218      * }
219      * else {
220      * // or throw exception???
221      * // can't make Number if dimension != 0
222      * return null;
223      * }
224      * }
225      */

226
227     /**
228      * Return a boolean value indiciating whether the currently stored
229      * value consists of different "types" of values (absolute, percent,
230      * and/or table-unit.)
231      */

232     private boolean isMixedType() {
233         int ntype = 0;
234         for (int t = valType; t != 0; t = t >> 1) {
235             if ((t & 1) != 0)
236                 ++ntype;
237         }
238         return ntype > 1;
239     }
240
241     /**
242      * Subtract the operand from the current value and return a new Numeric
243      * representing the result.
244      * @param op The value to subtract.
245      * @return A Numeric representing the result.
246      * @throws PropertyException If the dimension of the operand is different
247      * from the dimension of this Numeric.
248      */

249     public Numeric subtract(Numeric op) throws PropertyException {
250         // Check of same dimension
251
// Add together absolute and table units
252
// What about percentages??? Treat as colUnits if they can't be
253
// in same property!
254
if (dim == op.dim) {
255             PercentBase npcBase = ((valType & PC_LENGTH) != 0) ? pcBase
256                                   : op.pcBase;
257             // Subtract each type of value
258
return new Numeric(valType | op.valType, absValue - op.absValue,
259                                pcValue - op.pcValue,
260                                tcolValue - op.tcolValue, dim, npcBase);
261         } else {
262             throw new PropertyException("Can't add Numerics of different dimensions");
263         }
264     }
265
266     /**
267      * Add the operand from the current value and return a new Numeric
268      * representing the result.
269      * @param op The value to add.
270      * @return A Numeric representing the result.
271      * @throws PropertyException If the dimension of the operand is different
272      * from the dimension of this Numeric.
273      */

274     public Numeric add(Numeric op) throws PropertyException {
275         // Check of same dimension
276
// Add together absolute and table units
277
// What about percentages??? Treat as colUnits if they can't be
278
// in same property!
279
if (dim == op.dim) {
280             PercentBase npcBase = ((valType & PC_LENGTH) != 0) ? pcBase
281                                   : op.pcBase;
282             // Add each type of value
283
return new Numeric(valType | op.valType, absValue + op.absValue,
284                                pcValue + op.pcValue,
285                                tcolValue + op.tcolValue, dim, npcBase);
286         } else {
287             throw new PropertyException("Can't add Numerics of different dimensions");
288         }
289     }
290
291     /**
292      * Multiply the the current value by the operand and return a new Numeric
293      * representing the result.
294      * @param op The multiplier.
295      * @return A Numeric representing the result.
296      * @throws PropertyException If both Numerics have "mixed" type.
297      */

298     public Numeric multiply(Numeric op) throws PropertyException {
299         // Multiply together absolute units and add dimensions (exponents)
300
// What about percentages??? Treat as colUnits if they can't be
301
// in same property!
302
if (dim == 0) {
303             // This is a dimensionless quantity, ie. a "Number"
304
return new Numeric(op.valType, absValue * op.absValue,
305                                absValue * op.pcValue,
306                                absValue * op.tcolValue, op.dim, op.pcBase);
307         } else if (op.dim == 0) {
308             double opval = op.absValue;
309             return new Numeric(valType, opval * absValue, opval * pcValue,
310                                opval * tcolValue, dim, pcBase);
311         } else if (valType == op.valType &&!isMixedType()) {
312             // Check same relbase and pcbase ???
313
PercentBase npcBase = ((valType & PC_LENGTH) != 0) ? pcBase
314                                   : op.pcBase;
315             return new Numeric(valType, absValue * op.absValue,
316                                pcValue * op.pcValue,
317                                tcolValue * op.tcolValue, dim + op.dim,
318                                npcBase);
319         } else {
320             throw new PropertyException("Can't multiply mixed Numerics");
321         }
322     }
323
324     /**
325      * Divide the the current value by the operand and return a new Numeric
326      * representing the result.
327      * @param op The divisor.
328      * @return A Numeric representing the result.
329      * @throws PropertyException If both Numerics have "mixed" type.
330      */

331     public Numeric divide(Numeric op) throws PropertyException {
332         // Multiply together absolute units and add dimensions (exponents)
333
// What about percentages??? Treat as colUnits if they can't be
334
// in same property!
335
if (dim == 0) {
336             // This is a dimensionless quantity, ie. a "Number"
337
return new Numeric(op.valType, absValue / op.absValue,
338                                absValue / op.pcValue,
339                                absValue / op.tcolValue, -op.dim, op.pcBase);
340         } else if (op.dim == 0) {
341             double opval = op.absValue;
342             return new Numeric(valType, absValue / opval, pcValue / opval,
343                                tcolValue / opval, dim, pcBase);
344         } else if (valType == op.valType &&!isMixedType()) {
345             PercentBase npcBase = ((valType & PC_LENGTH) != 0) ? pcBase
346                                   : op.pcBase;
347             return new Numeric(valType,
348                                (valType == ABS_LENGTH ? absValue / op.absValue : 0.0),
349                                (valType == PC_LENGTH ? pcValue / op.pcValue : 0.0),
350                                (valType == TCOL_LENGTH ? tcolValue / op.tcolValue : 0.0),
351                                dim - op.dim, npcBase);
352         } else {
353             throw new PropertyException("Can't divide mixed Numerics.");
354         }
355     }
356
357     /**
358      * Return the absolute value of this Numeric.
359      * @return A new Numeric object representing the absolute value.
360      */

361     public Numeric abs() {
362         return new Numeric(valType, Math.abs(absValue), Math.abs(pcValue),
363                            Math.abs(tcolValue), dim, pcBase);
364     }
365
366     /**
367      * Return a Numeric which is the maximum of the current value and the
368      * operand.
369      * @throws PropertyException If the dimensions or value types of the
370      * object and the operand are different.
371      */

372     public Numeric max(Numeric op) throws PropertyException {
373         double rslt = 0.0;
374         // Only compare if have same dimension and value type!
375
if (dim == op.dim && valType == op.valType &&!isMixedType()) {
376             if (valType == ABS_LENGTH)
377                 rslt = absValue - op.absValue;
378             else if (valType == PC_LENGTH)
379                 rslt = pcValue - op.pcValue;
380             else if (valType == TCOL_LENGTH)
381                 rslt = tcolValue - op.tcolValue;
382             if (rslt > 0.0)
383                 return this;
384             else
385                 return op;
386         }
387         throw new PropertyException("Arguments to max() must have same dimension and value type.");
388     }
389
390     /**
391      * Return a Numeric which is the minimum of the current value and the
392      * operand.
393      * @throws PropertyException If the dimensions or value types of the
394      * object and the operand are different.
395      */

396     public Numeric min(Numeric op) throws PropertyException {
397         double rslt = 0.0;
398         // Only compare if have same dimension and value type!
399
if (dim == op.dim && valType == op.valType &&!isMixedType()) {
400             if (valType == ABS_LENGTH)
401                 rslt = absValue - op.absValue;
402             else if (valType == PC_LENGTH)
403                 rslt = pcValue - op.pcValue;
404             else if (valType == TCOL_LENGTH)
405                 rslt = tcolValue - op.tcolValue;
406             if (rslt > 0.0)
407                 return op;
408             else
409                 return this;
410         }
411         throw new PropertyException("Arguments to min() must have same dimension and value type.");
412     }
413
414 }
415
Popular Tags