001: /*
002: * GeoTools - OpenSource mapping toolkit
003: * http://geotools.org
004: * (C) 2005-2006, GeoTools Project Managment Committee (PMC)
005: *
006: * This library is free software; you can redistribute it and/or
007: * modify it under the terms of the GNU Lesser General Public
008: * License as published by the Free Software Foundation;
009: * version 2.1 of the License.
010: *
011: * This library is distributed in the hope that it will be useful,
012: * but WITHOUT ANY WARRANTY; without even the implied warranty of
013: * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
014: * Lesser General Public License for more details.
015: */
016: package org.geotools.feature.visitor;
017:
018: /**
019: *
020: * @source $URL: http://svn.geotools.org/geotools/tags/2.4.1/modules/library/main/src/main/java/org/geotools/feature/visitor/CalcUtil.java $
021: */
022: public class CalcUtil {
023:
024: /**
025: * Sums an array of numbers together while using the correct class type.
026: *
027: * @param numbers
028: *
029: * @return the sum contained in the most appropriate number class
030: */
031: static Number sum(Number[] numbers) {
032: Number newSum = (Number) getObject(numbers);
033:
034: if (newSum == null) {
035: return null;
036: }
037:
038: //Integer, Long, Float, Double
039: if (newSum instanceof Integer) {
040: int sum = 0;
041: int nextValue;
042:
043: for (int i = 0; i < numbers.length; i++) {
044: nextValue = numbers[i].intValue();
045: sum += nextValue;
046: }
047:
048: newSum = new Integer(sum);
049: } else if (newSum instanceof Long) {
050: long sum = 0;
051: long nextValue;
052:
053: for (int i = 0; i < numbers.length; i++) {
054: nextValue = numbers[i].longValue();
055: sum += nextValue;
056: }
057:
058: newSum = new Long(sum);
059: } else if (newSum instanceof Float) {
060: float sum = 0;
061: float nextValue;
062:
063: for (int i = 0; i < numbers.length; i++) {
064: nextValue = numbers[i].floatValue();
065: sum += nextValue;
066: }
067:
068: newSum = new Float(sum);
069: } else if (newSum instanceof Double) {
070: double sum = 0;
071: double nextValue;
072:
073: for (int i = 0; i < numbers.length; i++) {
074: nextValue = numbers[i].doubleValue();
075: sum += nextValue;
076: }
077:
078: newSum = new Double(sum);
079: } else {
080: return null;
081: }
082:
083: return newSum;
084: }
085:
086: /**
087: * Divides num1 by num2, and return the result in the correct number class.
088: *
089: * @param num1 numerator
090: * @param num2 denominator
091: * @return num1/num2 in the most appropriate class
092: */
093: static Number divide(Number num1, Number num2) {
094: Number[] both = new Number[2];
095: both[0] = num1;
096: both[1] = num2;
097:
098: Number division = (Number) getObject(both);
099:
100: if (division == null) {
101: return null;
102: }
103:
104: //Integer, Long, Float, Double
105: if (division instanceof Integer) {
106: //we've got 2 integers, but we're going to use double anyways
107: return new Double(num1.doubleValue() / num2.doubleValue());
108: } else if (division instanceof Long) {
109: return new Long(num1.longValue() / num2.longValue());
110: } else if (division instanceof Float) {
111: return new Float(num1.floatValue() / num2.floatValue());
112: } else if (division instanceof Double) {
113: return new Double(num1.doubleValue() / num2.doubleValue());
114: } else {
115: return null;
116: }
117: }
118:
119: /**
120: * Calculates the average, and returns it in the correct class.
121: * @param numbers
122: */
123: static Number average(Number[] numbers) {
124: Number sum = sum(numbers);
125:
126: return divide(sum, new Integer(numbers.length));
127: }
128:
129: /**
130: * Determines the most appropriate class to use for a multiclass calculation.
131: *
132: * @param objects
133: * @return the most
134: */
135: static Class bestClass(Object[] objects) {
136: boolean hasInt = false;
137: boolean hasFloat = false;
138: boolean hasLong = false;
139: boolean hasDouble = false;
140: boolean hasString = false;
141:
142: for (int i = 0; i < objects.length; i++) {
143: if (objects[i] instanceof Double) {
144: hasDouble = true;
145: } else if (objects[i] instanceof Float) {
146: hasFloat = true;
147: } else if (objects[i] instanceof Long) {
148: hasLong = true;
149: } else if (objects[i] instanceof Integer) {
150: hasInt = true;
151: } else if (objects[i] instanceof String) {
152: hasString = true;
153: }
154: }
155:
156: if (hasString) {
157: return String.class;
158: } else if (hasDouble) {
159: return Double.class;
160: } else if (hasFloat) {
161: return Float.class;
162: } else if (hasLong) {
163: return Long.class;
164: } else if (hasInt) {
165: return Integer.class;
166: } else { //it's a type we don't have here yet
167:
168: return null;
169: }
170: }
171:
172: /**
173: * Casts an object to the specified type
174: *
175: * @param var
176: * @param type
177: *
178: */
179: static Object convert(Object var, Class type) {
180: if (var instanceof Number) { //use number conversion
181:
182: Number newNum = (Number) var;
183:
184: if (type == Integer.class) {
185: return new Integer(newNum.intValue());
186: } else if (type == Long.class) {
187: return new Long(newNum.longValue());
188: } else if (type == Float.class) {
189: return new Float(newNum.floatValue());
190: } else if (type == Double.class) {
191: return new Double(newNum.doubleValue());
192: } else if (type == String.class) {
193: return new String(newNum.toString());
194: }
195: } else { //direct cast
196:
197: if (type == Integer.class) {
198: return new Integer(((Integer) var).intValue());
199: } else if (type == Long.class) {
200: return new Long(((Long) var).longValue());
201: } else if (type == Float.class) {
202: return new Float(((Float) var).floatValue());
203: } else if (type == Double.class) {
204: return new Double(((Double) var).doubleValue());
205: } else if (type == String.class) {
206: return new String(var.toString());
207: }
208: }
209:
210: return null;
211: }
212:
213: static Object convert(Object[] objects, Object var) {
214: Object newVar = getObject(objects);
215:
216: if (newVar instanceof Number) {
217: Number newNum = (Number) var;
218:
219: if (newVar instanceof Integer) {
220: return new Integer(newNum.intValue());
221: } else if (newVar instanceof Long) {
222: return new Long(newNum.longValue());
223: } else if (newVar instanceof Float) {
224: return new Float(newNum.floatValue());
225: } else if (newVar instanceof Double) {
226: return new Double(newNum.doubleValue());
227: } else {
228: return null;
229: }
230: } else if (newVar instanceof String) {
231: return new String((String) newVar);
232: } else {
233: //TODO: add other classes
234: return null;
235: }
236: }
237:
238: /**
239: * Given an array of objects, traverses the array and determines the most
240: * suitable data type to perform the calculation in. An empty object of
241: * the correct class is returned;
242: *
243: * @param objects
244: *
245: */
246: static Object getObject(Object[] objects) {
247: Class bestClass = bestClass(objects);
248:
249: if (bestClass == String.class) {
250: return new String(""); //$NON-NLS-1$
251: } else if (bestClass == Double.class) {
252: return new Double(0);
253: } else if (bestClass == Float.class) {
254: return new Float(0);
255: } else if (bestClass == Float.class) {
256: return new Long(0);
257: } else if (bestClass == Integer.class) {
258: return new Integer(0);
259: } else { //it's a type we don't have here yet
260: return null;
261: }
262: }
263:
264: /**
265: * Similar to java.lang.Comparable.compareTo, but can handle 2 different
266: * data types.
267: *
268: * @param val1
269: * @param val2
270: *
271: */
272: static int compare(Comparable val1, Comparable val2) {
273: if (val1.getClass() == val2.getClass()) {
274: //both the same type, no conversion is necessary.
275: return val1.compareTo(val2);
276: }
277:
278: //find most appropriate class
279: Object[] objects = new Object[] { val1, val2 };
280: Class bestClass = bestClass(objects);
281:
282: if (bestClass != val1.getClass()) {
283: val1 = (Comparable) convert(val1, bestClass);
284: }
285:
286: if (bestClass != val2.getClass()) {
287: val2 = (Comparable) convert(val2, bestClass);
288: }
289:
290: //now do the comparison
291: return val1.compareTo(val2);
292: }
293: }
|