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: * Created on May 29, 2005
019: *
020: */
021: package org.apache.poi.hssf.record.formula.functions;
022:
023: import org.apache.poi.hssf.record.formula.eval.AreaEval;
024: import org.apache.poi.hssf.record.formula.eval.ErrorEval;
025: import org.apache.poi.hssf.record.formula.eval.Eval;
026: import org.apache.poi.hssf.record.formula.eval.NumberEval;
027: import org.apache.poi.hssf.record.formula.eval.RefEval;
028: import org.apache.poi.hssf.record.formula.eval.ValueEval;
029: import org.apache.poi.hssf.record.formula.eval.ValueEvalToNumericXlator;
030:
031: /**
032: * @author Amol S. Deshmukh < amolweb at ya hoo dot com >
033: *
034: */
035: public abstract class XYNumericFunction extends NumericFunction {
036: protected static final int X = 0;
037: protected static final int Y = 1;
038:
039: private static final ValueEvalToNumericXlator DEFAULT_NUM_XLATOR = new ValueEvalToNumericXlator(
040: (short) (ValueEvalToNumericXlator.BOOL_IS_PARSED
041: | ValueEvalToNumericXlator.REF_BOOL_IS_PARSED
042: | ValueEvalToNumericXlator.EVALUATED_REF_BOOL_IS_PARSED
043: //| ValueEvalToNumericXlator.STRING_IS_PARSED
044: | ValueEvalToNumericXlator.REF_STRING_IS_PARSED | ValueEvalToNumericXlator.EVALUATED_REF_STRING_IS_PARSED
045: //| ValueEvalToNumericXlator.STRING_TO_BOOL_IS_PARSED
046: //| ValueEvalToNumericXlator.REF_STRING_TO_BOOL_IS_PARSED
047: //| ValueEvalToNumericXlator.STRING_IS_INVALID_VALUE
048: //| ValueEvalToNumericXlator.REF_STRING_IS_INVALID_VALUE
049: ));
050:
051: /**
052: * this is the default impl for the factory method getXlator
053: * of the super class NumericFunction. Subclasses can override this method
054: * if they desire to return a different ValueEvalToNumericXlator instance
055: * than the default.
056: */
057: protected ValueEvalToNumericXlator getXlator() {
058: return DEFAULT_NUM_XLATOR;
059: }
060:
061: protected int getMaxNumOperands() {
062: return 30;
063: }
064:
065: /**
066: * Returns a double array that contains values for the numeric cells
067: * from among the list of operands. Blanks and Blank equivalent cells
068: * are ignored. Error operands or cells containing operands of type
069: * that are considered invalid and would result in #VALUE! error in
070: * excel cause this function to return null.
071: *
072: * @param xops
073: * @param yops
074: * @param srcRow
075: * @param srcCol
076: */
077: protected double[][] getNumberArray(Eval[] xops, Eval[] yops,
078: int srcRow, short srcCol) {
079: double[][] retval = new double[2][30];
080: int count = 0;
081:
082: if (xops.length > getMaxNumOperands()
083: || yops.length > getMaxNumOperands()
084: || xops.length != yops.length) {
085: retval = null;
086: } else {
087:
088: for (int i = 0, iSize = xops.length; i < iSize; i++) {
089: Eval xEval = xops[i];
090: Eval yEval = yops[i];
091:
092: if (isNumberEval(xEval) && isNumberEval(yEval)) {
093: retval[X] = ensureCapacity(retval[X], count);
094: retval[Y] = ensureCapacity(retval[Y], count);
095: retval[X][count] = getDoubleValue(xEval);
096: retval[Y][count] = getDoubleValue(yEval);
097: if (Double.isNaN(retval[X][count])
098: || Double.isNaN(retval[Y][count])) {
099: retval = null;
100: break;
101: }
102: count++;
103: }
104: }
105: }
106:
107: if (retval != null) {
108: double[][] temp = retval;
109: retval[X] = trimToSize(retval[X], count);
110: retval[Y] = trimToSize(retval[Y], count);
111: }
112:
113: return retval;
114: }
115:
116: protected double[][] getValues(Eval[] operands, int srcCellRow,
117: short srcCellCol) {
118: double[][] retval = null;
119:
120: outer: do {
121: if (operands.length == 2) {
122: Eval[] xEvals = new Eval[1];
123: Eval[] yEvals = new Eval[1];
124: if (operands[X] instanceof AreaEval) {
125: AreaEval ae = (AreaEval) operands[0];
126: xEvals = ae.getValues();
127: } else if (operands[X] instanceof ErrorEval) {
128: break outer;
129: } else {
130: xEvals[0] = operands[X];
131: }
132:
133: if (operands[Y] instanceof AreaEval) {
134: AreaEval ae = (AreaEval) operands[Y];
135: yEvals = ae.getValues();
136: } else if (operands[Y] instanceof ErrorEval) {
137: break outer;
138: } else {
139: yEvals[0] = operands[Y];
140: }
141:
142: retval = getNumberArray(xEvals, yEvals, srcCellRow,
143: srcCellCol);
144: }
145: } while (false);
146:
147: return retval;
148: }
149:
150: protected static double[] ensureCapacity(double[] arr, int pos) {
151: double[] temp = arr;
152: while (pos >= arr.length) {
153: arr = new double[arr.length << 2];
154: }
155: if (temp.length != arr.length)
156: System.arraycopy(temp, 0, arr, 0, temp.length);
157: return arr;
158: }
159:
160: protected static double[] trimToSize(double[] arr, int len) {
161: double[] tarr = arr;
162: if (arr.length > len) {
163: tarr = new double[len];
164: System.arraycopy(arr, 0, tarr, 0, len);
165: }
166: return tarr;
167: }
168:
169: protected static boolean isNumberEval(Eval eval) {
170: boolean retval = false;
171:
172: if (eval instanceof NumberEval) {
173: retval = true;
174: } else if (eval instanceof RefEval) {
175: RefEval re = (RefEval) eval;
176: ValueEval ve = re.getInnerValueEval();
177: retval = (ve instanceof NumberEval);
178: }
179:
180: return retval;
181: }
182:
183: protected static double getDoubleValue(Eval eval) {
184: double retval = 0;
185: if (eval instanceof NumberEval) {
186: NumberEval ne = (NumberEval) eval;
187: retval = ne.getNumberValue();
188: } else if (eval instanceof RefEval) {
189: RefEval re = (RefEval) eval;
190: ValueEval ve = re.getInnerValueEval();
191: retval = (ve instanceof NumberEval) ? ((NumberEval) ve)
192: .getNumberValue() : Double.NaN;
193: } else if (eval instanceof ErrorEval) {
194: retval = Double.NaN;
195: }
196: return retval;
197: }
198: }
|