package org.simantics.maps.sg; import java.util.Locale; /** * @author Tuukka Lehtonen */ class Formatting { private static final transient double EPSILON = 0.01; private static final transient double TRIM_THRESHOLD_MAX_VALUE = Math.pow(10, 4); private static final transient String[] SI_UNIT_LARGE_PREFIXES = { "k", "M", "G", "T", "P", "E", "Z", "Y" }; public static enum FormatMode { LIMIT_DIGITS, LIMIT_DECIMALS, } public static String formatValue(double value, int max, boolean removeTrailingZeros, FormatMode formatMode) { return formatValue(value, max, removeTrailingZeros, formatMode, TRIM_THRESHOLD_MAX_VALUE); } public static String formatValue(double value, int max, boolean removeTrailingZeros, FormatMode formatMode, double trimThresholdMaxValue) { return formatValue(value, max, removeTrailingZeros, formatMode, trimThresholdMaxValue, true); } public static String formatValue(double value, int max, boolean removeTrailingZeros, FormatMode formatMode, double trimThresholdMaxValue, boolean trimLargeValues) { //System.out.println("formatValue(" + value + ", " + max + ", " + removeTrailingZeros + ", " + formatMode + ", " + trimThresholdMaxValue + ", " + trimLargeValues + ")"); int allowedDecimals = max; if (formatMode == FormatMode.LIMIT_DIGITS) { int magnitude = (int) Math.ceil(Math.log10(Math.abs(value))); //System.out.println("magnitude(" + value + "): " + magnitude); allowedDecimals -= Math.abs(magnitude); if (allowedDecimals < 0) allowedDecimals = 0; //System.out.println("allowedDecimals: " + allowedDecimals); } String valueStr = String.format(Locale.US, "%." + allowedDecimals + "f", value); if (allowedDecimals > 0) { if (removeTrailingZeros) { for (int trunc = valueStr.length() - 1; trunc > 0; --trunc) { char ch = valueStr.charAt(trunc); if (ch == '.') { valueStr = valueStr.substring(0, trunc); break; } if (ch != '0') { valueStr = valueStr.substring(0, trunc + 1); break; } } } if (Math.abs(value) + EPSILON > trimThresholdMaxValue) { // Cut anything beyond a possible decimal dot out since they // should not show anyway. This is a complete hack that tries to // circumvent floating-point inaccuracy problems. int dotIndex = valueStr.lastIndexOf('.'); if (dotIndex > -1) { valueStr = valueStr.substring(0, dotIndex); } } } if (valueStr.equals("-0")) valueStr = "0"; if (trimLargeValues) { double trimValue = value; if (Math.abs(value) + EPSILON >= trimThresholdMaxValue) { for (int i = 0; Math.abs(trimValue) + EPSILON >= trimThresholdMaxValue; ++i) { double trim = trimValue / 1000; if (Math.abs(trim) - EPSILON < trimThresholdMaxValue) { valueStr = valueStr.substring(0, valueStr.length() - (i + 1) * 3); valueStr += SI_UNIT_LARGE_PREFIXES[i]; break; } trimValue = trim; } } } //System.out.println("formatted result: " + valueStr); return valueStr; } }