// // Convert.java // /* VisAD system for interactive analysis and visualization of numerical data. Copyright (C) 1996 - 2017 Bill Hibbard, Curtis Rueden, Tom Rink, Dave Glowacki, Steve Emmerson, Tom Whittaker, Don Murray, and Tommy Jasmin. This library is free software; you can redistribute it and/or modify it under the terms of the GNU Library General Public License as published by the Free Software Foundation; either version 2 of the License, or (at your option) any later version. 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 Library General Public License for more details. You should have received a copy of the GNU Library General Public License along with this library; if not, write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA */ package visad.browser; /** * Utility methods for various conversions between primitive data types. */ public class Convert { /** * Converts an array of ints to an array of bytes. Each integer is cut into * four byte-size pieces, making the resulting byte array four times the * length of the input int array. * * @param ints The array of ints to be converted to a byte array * * @return An array of bytes corresponding to the original int array. */ public static byte[] intToBytes(int[] ints) { int len = ints.length; byte[] bytes = new byte[4 * len]; for (int i = 0; i < len; i++) { int q = ints[i]; bytes[4 * i] = (byte) (q & 0x000000ff); bytes[4 * i + 1] = (byte) ((q & 0x0000ff00) >> 8); bytes[4 * i + 2] = (byte) ((q & 0x00ff0000) >> 16); bytes[4 * i + 3] = (byte) ((q & 0xff000000) >> 24); } return bytes; } /** * Converts an array of bytes to an array of ints. Each group of four bytes * form a single int, making the resulting int array one fourth the length * of the input byte array. Note that trailing elements of the bytes array * will be ignored. * * @param bytes The array of bytes to be converted to an int array * * @return An array of ints corresponding to the original byte array. */ public static int[] bytesToInt(byte[] bytes) { int len = bytes.length / 4; int[] ints = new int[len]; for (int i = 0; i < len; i++) { // This byte decoding method is not very good; is there a better way? int q3 = bytes[4 * i + 3] << 24; int q2 = bytes[4 * i + 2] << 16; int q1 = bytes[4 * i + 1] << 8; int q0 = bytes[4 * i]; if (q2 < 0) q2 += 16777216; if (q1 < 0) q1 += 65536; if (q0 < 0) q0 += 256; ints[i] = q3 | q2 | q1 | q0; } return ints; } /** * Escape value for an RLE encoded sequence. */ private static final int RLE_ESCAPE = Integer.MIN_VALUE; /** * Encodes the given array of ints using a run-length scheme. * * @param array The array of ints to RLE-encode * * @return An RLE-encoded array of ints. */ public static int[] encodeRLE(int[] array) { int len = array.length; int[] temp = new int[len]; int p = 0; for (int i = 0; i < len;) { int q = array[i]; int count = 0; while (i < len && q == array[i]) { count++; i++; } if (count < 4) { // no gain from RLE; save values directly for (int z = 0; z < count; z++) temp[p++] = q; } else { // compress data using RLE temp[p++] = RLE_ESCAPE; temp[p++] = q; temp[p++] = count; } } // trim encoded array int[] encoded = new int[p]; System.arraycopy(temp, 0, encoded, 0, p); return encoded; } /** * Decodes the given array of ints from a run-length encoding. * * @param array The RLE-encoded array of ints to decode * * @return A decoded array of ints. */ public static int[] decodeRLE(int[] array) { // compute size of decoded array int count = 0; int i = 0; while (i < array.length) { if (array[i] == RLE_ESCAPE) { count += array[i + 2]; i += 3; } else { count++; i++; } } // allocate decoded array int[] decoded = new int[count]; int p = 0; // decode RLE sequence for (i = 0; i < array.length; i++) { int q = array[i]; if (q == RLE_ESCAPE) { int val = array[++i]; int cnt = array[++i]; for (int z = 0; z < cnt; z++) decoded[p++] = val; } else decoded[p++] = q; } return decoded; } /** * Extracts a double from a string. */ public static double getDouble(String s) { double d = Double.NaN; try { d = Double.valueOf(s).doubleValue(); } catch (NumberFormatException exc) { } return d; } /** * Extracts a float from a string. */ public static float getFloat(String s) { float f = Float.NaN; if (s != null) { try { f = Float.valueOf(s).floatValue(); } catch (NumberFormatException exc) { } } return f; } /** * Extracts a boolean from a string. */ public static boolean getBoolean(String s) { if (s == null) return false; char c = s.trim().charAt(0); return c == 'T' || c == 't'; } /** * Extracts an integer from a string. */ public static int getInt(String s) { int i = 0; if (s != null) { try { i = Integer.parseInt(s); } catch (NumberFormatException exc) { } } return i; } /** * Number of significant digits after the decimal point. */ public static final int PLACES = 3; /** Mode where shortString rounds to the nearest value. */ public static final int ROUND_NEAREST = 1; /** Mode where shortString rounds to the lower value. */ public static final int ROUND_DOWN = 2; /** Mode where shortString rounds to the higher value. */ public static final int ROUND_UP = 3; /** * Gets a reasonably short string representation of a double * for use in a graphical user interface. The number will be rounded * to the nearest integer. */ public static String shortString(double val) { return shortString(val, ROUND_NEAREST); } /** * Gets a reasonably short string representation of a double * for use in a graphical user interface. Mode indicates the method * used to deal insignificant digits: ROUND_NEAREST, ROUND_UP or ROUND_DOWN. */ public static String shortString(double val, int mode) { // remember whether or not the number is negative boolean negative = (val < 0.0); double origVal = val; // now we only need to deal with a positive number val = Math.abs(val); if (val < 0.001) { for (int i = 1; i < 30; i++) { val *= 10.0; origVal *= 10.0; if (val >= 1.0) { return shortString(origVal) + "E-" + i; } } } // build multiplier for saving significant digits // also build value used to round up insignificant digits int mult = 1; float round; if (mode == ROUND_DOWN) round = negative ? 1 : 0; else if (mode == ROUND_UP) round = negative ? 0 : 1; else round = 0.5f; // mode == ROUND_NEAREST (default) for (int p = PLACES; p > 0; p--) { mult *= 10; round /= 10; } // break into digits before (preDot) and after (postDot) the decimal point long l = (long) ((val + round) * mult); long preDot = l / mult; int postDot = (int )(l % mult); // format the pre-decimal point number // Integer.toString() is faster than Long.toString(); use it if possible String num; if (preDot <= Integer.MAX_VALUE) { num = Integer.toString((int )preDot); } else { num = Long.toString(preDot); } // if there's nothing after the decimal point, use the whole number if (postDot == 0) { // make sure we don't return "-0" if (negative && preDot != 0) { return "-" + num; } return num; } // start building the string StringBuffer buf = new StringBuffer(num.length() + 5); // add sign (if necessary), pre-decimal point digits and decimal point if (negative) { buf.append('-'); } buf.append(num); buf.append('.'); // format the post-decimal point digits num = Integer.toString(postDot); // add leading zeros if necessary int nlen = num.length(); for (int p = PLACES; p > nlen; p--) { buf.append('0'); } // add actual digits buf.append(num); // return the final string return buf.toString(); } }