/* * GeoTools - The Open Source Java GIS Toolkit * http://geotools.org * * (C) 2005-2008, Open Source Geospatial Foundation (OSGeo) * * This library is free software; you can redistribute it and/or * modify it under the terms of the GNU Lesser General Public * License as published by the Free Software Foundation; * version 2.1 of the License. * * This library is distributed in the hope that it will be useful, * but WITHOUT ANY WARRANTY; without even the implied warranty of * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU * Lesser General Public License for more details. */ package org.geotools.feature.visitor; /** * * * @source $URL$ */ public class CalcUtil { /** * Sums an array of numbers together while using the correct class type. * * @param numbers * * @return the sum contained in the most appropriate number class */ static Number sum(Number[] numbers) { Number newSum = (Number) getObject(numbers); if (newSum == null) { return null; } //Integer, Long, Float, Double if (newSum instanceof Integer) { int sum = 0; int nextValue; for (int i = 0; i < numbers.length; i++) { nextValue = numbers[i].intValue(); sum += nextValue; } newSum = new Integer(sum); } else if (newSum instanceof Long) { long sum = 0; long nextValue; for (int i = 0; i < numbers.length; i++) { nextValue = numbers[i].longValue(); sum += nextValue; } newSum = new Long(sum); } else if (newSum instanceof Float) { float sum = 0; float nextValue; for (int i = 0; i < numbers.length; i++) { nextValue = numbers[i].floatValue(); sum += nextValue; } newSum = new Float(sum); } else if (newSum instanceof Double) { double sum = 0; double nextValue; for (int i = 0; i < numbers.length; i++) { nextValue = numbers[i].doubleValue(); sum += nextValue; } newSum = new Double(sum); } else { return null; } return newSum; } /** * Divides num1 by num2, and return the result in the correct number class. * * @param num1 numerator * @param num2 denominator * @return num1/num2 in the most appropriate class */ static Number divide(Number num1, Number num2) { Number[] both = new Number[2]; both[0] = num1; both[1] = num2; Number division = (Number) getObject(both); if (division == null) { return null; } //Integer, Long, Float, Double if (division instanceof Integer) { //we've got 2 integers, but we're going to use double anyways return new Double(num1.doubleValue() / num2.doubleValue()); } else if (division instanceof Long) { return new Long(num1.longValue() / num2.longValue()); } else if (division instanceof Float) { return new Float(num1.floatValue() / num2.floatValue()); } else if (division instanceof Double) { return new Double(num1.doubleValue() / num2.doubleValue()); } else { return null; } } /** * Calculates the average, and returns it in the correct class. * @param numbers */ static Number average(Number[] numbers) { Number sum = sum(numbers); return divide(sum, new Integer(numbers.length)); } /** * Determines the most appropriate class to use for a multiclass calculation. * * @param objects * @return the most */static Class bestClass(Object[] objects) { boolean hasInt = false; boolean hasFloat = false; boolean hasLong = false; boolean hasDouble = false; boolean hasString = false; for (int i = 0; i < objects.length; i++) { if (objects[i] instanceof Double) { hasDouble = true; } else if (objects[i] instanceof Float) { hasFloat = true; } else if (objects[i] instanceof Long) { hasLong = true; } else if (objects[i] instanceof Integer) { hasInt = true; } else if (objects[i] instanceof String) { hasString = true; } } if (hasString) { return String.class; } else if (hasDouble) { return Double.class; } else if (hasFloat) { return Float.class; } else if (hasLong) { return Long.class; } else if (hasInt) { return Integer.class; } else { //it's a type we don't have here yet return null; } } /** * Casts an object to the specified type * * @param var * @param type * */ static Object convert(Object var, Class type) { if (var instanceof Number) { //use number conversion Number newNum = (Number) var; if (type == Integer.class) { return new Integer(newNum.intValue()); } else if (type == Long.class) { return new Long(newNum.longValue()); } else if (type == Float.class) { return new Float(newNum.floatValue()); } else if (type == Double.class) { return new Double(newNum.doubleValue()); } else if (type == String.class) { return new String(newNum.toString()); } } else { //direct cast if (type == Integer.class) { return new Integer(((Integer) var).intValue()); } else if (type == Long.class) { return new Long(((Long) var).longValue()); } else if (type == Float.class) { return new Float(((Float) var).floatValue()); } else if (type == Double.class) { return new Double(((Double) var).doubleValue()); } else if (type == String.class) { return new String(var.toString()); } } return null; } static Object convert(Object[] objects, Object var) { Object newVar = getObject(objects); if (newVar instanceof Number) { Number newNum = (Number) var; if (newVar instanceof Integer) { return new Integer(newNum.intValue()); } else if (newVar instanceof Long) { return new Long(newNum.longValue()); } else if (newVar instanceof Float) { return new Float(newNum.floatValue()); } else if (newVar instanceof Double) { return new Double(newNum.doubleValue()); } else { return null; } } else if (newVar instanceof String) { return new String((String) newVar); } else { //TODO: add other classes return null; } } /** * Given an array of objects, traverses the array and determines the most * suitable data type to perform the calculation in. An empty object of * the correct class is returned; * * @param objects * */ static Object getObject(Object[] objects) { Class bestClass = bestClass(objects); if (bestClass == String.class) { return new String(""); //$NON-NLS-1$ } else if (bestClass == Double.class) { return new Double(0); } else if (bestClass == Float.class) { return new Float(0); } else if (bestClass == Long.class) { return new Long(0); } else if (bestClass == Integer.class) { return new Integer(0); } else { //it's a type we don't have here yet return null; } } /** * Similar to java.lang.Comparable.compareTo, but can handle 2 different * data types. * * @param val1 * @param val2 * */ static int compare(Comparable val1, Comparable val2) { if (val1.getClass() == val2.getClass()) { //both the same type, no conversion is necessary. return val1.compareTo(val2); } //find most appropriate class Object[] objects = new Object[] { val1, val2 }; Class bestClass = bestClass(objects); if (bestClass != val1.getClass()) { val1 = (Comparable) convert(val1, bestClass); } if (bestClass != val2.getClass()) { val2 = (Comparable) convert(val2, bestClass); } //now do the comparison return val1.compareTo(val2); } }